ZQuest Classic Coverage Report


Directory: src/
File: src/gui/jwin.cpp
Date: 2024-10-16 04:38:54
Exec Total Coverage
Lines: 198 5701 3.5%
Functions: 16 151 10.6%
Branches: 251 4417 5.7%

Line Branch Exec Source
1 #include <ctype.h>
2 #include <cstring>
3 #include "base/zapp.h"
4 #include "base/zc_alleg.h"
5 #include <allegro/internal/aintern.h>
6 #include "gui/jwin.h"
7 #include "base/zdefs.h"
8 #include "gui/editbox.h"
9 #include <iostream>
10 #include <sstream>
11 #include "base/zsys.h"
12 #include <stdio.h>
13 #include "base/util.h"
14 #include "pal.h"
15 #include "gui/tabpanel.h"
16 #include "gui/text_field.h"
17 #include "dialog/info.h"
18 #include "drawing.h"
19 using namespace util;
20 using std::string;
21 using std::istringstream;
22
23 void update_hw_screen();
24 extern int32_t zq_screen_w, zq_screen_h;
25 extern int32_t joystick_index;
26 int CheckerCol1 = 7, CheckerCol2 = 8;
27
28 int32_t abc_patternmatch = 1;
29
30 char abc_keypresses[1024] = {0};
31 void wipe_abc_keypresses() { memset(abc_keypresses, 0, 1024); }
32
33 /* these are provided for external use */
34 int32_t jwin_colors[jcMAX] =
35 {
36 0xC0C0C0,0xF0F0F0,0xD0D0D0,0x808080,0x404040,0x000000,
37 0x000080,0x00F0F0,0xFFFFFF,0xFFFFFF,0x000000,0x000080,0xFFFFFF
38 };
39
40 int32_t scheme[jcMAX] =
41 {
42 0xC0C0C0,0xF0F0F0,0xD0D0D0,0x808080,0x404040,0x000000,
43 0x000080,0x00F0F0,0xFFFFFF,0xFFFFFF,0x000000,0x000080,0xFFFFFF
44 };
45
46 int32_t jwin_pal[jcMAX] = {0};
47
48 // A pointer to this variable is used to identify the DIALOG belonging to
49 // the DialogRunner. It isn't used for anything else.
50 char newGuiMarker;
51
52 int32_t new_gui_event(DIALOG* d, guiEvent event)
53 {
54 for(int32_t i = 0; true; --d, ++i)
55 {
56 if(d->dp3 == &newGuiMarker)
57 {
58 d->d1 = i;
59 return d->proc(MSG_GUI_EVENT, d, event);
60 }
61 }
62
63 return -1;
64 }
65
66 void close_new_gui_dlg(DIALOG* d);
67
68 int32_t bound(int32_t x,int32_t low,int32_t high)
69 {
70 if(x<low) x=low;
71
72 if(x>high) x=high;
73
74 return x;
75 }
76 /*
77 float bound(float x,float low,float high)
78 {
79 if(x<low) x=low;
80 if(x>high) x=high;
81 return x;
82 }
83 */
84
85 int32_t get_selected_tab(TABPANEL* panel)
86 {
87 for(int32_t i=0; panel[i].text; ++i)
88 {
89 if((panel[i].flags&D_SELECTED)!=0)
90 return i;
91 }
92 return -1;
93 }
94
95 /* jwin_set_colors:
96 * Loads a set of colors in 0xRRGGBB or 256-color-indexed format
97 * into the current color scheme using the appropriate color depth
98 * conversions.
99 */
100 110 void jwin_set_colors(int32_t *colors)
101 {
102 110 int32_t i = 0;
103
104
1/2
✓ Branch 0 taken 110 times.
✗ Branch 1 not taken.
110 if(bitmap_color_depth(screen) == 8)
105 {
106 // use color indices
107
2/2
✓ Branch 0 taken 110 times.
✓ Branch 1 taken 2310 times.
2420 for(; i<jcMAX; i++)
108 2310 scheme[i] = colors[i];
109 110 }
110 else
111 {
112 // 0xRRGGBB format
113 for(; i<jcMAX; i++)
114 scheme[i] = makecol(colors[i]>>16, (colors[i]>>8)&0xFF, colors[i]&0xFF);
115 }
116 110 }
117
118 /* jwin_set_dialog_color:
119 * Sets the foreground and background colors of all the objects in a dialog.
120 *
121 * Needs work!
122 */
123 void jwin_set_dialog_color(DIALOG *dialog)
124 {
125 int32_t c;
126
127 for(c=0; dialog[c].proc; c++)
128 {
129 dialog[c].fg = scheme[jcMEDDARK];
130 dialog[c].bg = scheme[jcBOX];
131 }
132 }
133
134 /* jwin_draw_frame:
135 * Draws a frame using the specified style.
136 */
137 void jwin_draw_frame(BITMAP *dest,int32_t x,int32_t y,int32_t w,int32_t h,int32_t style)
138 {
139 optional<int> c1,c2,c3,c4;
140
141 switch(style)
142 {
143 case FR_INVIS:
144 return;
145 case FR_BOX:
146 c1 = jcLIGHT;
147 c2 = jcMEDLT;
148 c3 = jcMEDDARK;
149 c4 = jcDARK;
150 break;
151
152 case FR_INV:
153 c1 = jcDARK;
154 c2 = jcMEDDARK;
155 c3 = jcMEDLT;
156 c4 = jcLIGHT;
157 break;
158
159 case FR_DEEP:
160 c1 = jcMEDDARK;
161 c2 = jcDARK;
162 c3 = jcMEDLT;
163 c4 = jcLIGHT;
164 break;
165
166 case FR_DARK:
167 c1 = jcDARK;
168 c2 = jcMEDDARK;
169 c3 = jcMEDDARK;
170 c4 = jcDARK;
171 break;
172
173 case FR_ETCHED:
174 c1 = jcMEDDARK;
175 c2 = jcLIGHT;
176 c3 = jcMEDDARK;
177 c4 = jcLIGHT;
178 break;
179
180 case FR_MEDDARK:
181 c1 = jcMEDDARK;
182 c2 = jcBOX;
183 c3 = jcBOX;
184 c4 = jcMEDDARK;
185 break;
186
187 case FR_MENU:
188 c1 = jcLIGHT;
189 c4 = jcMEDDARK;
190 break;
191 case FR_MENU_INV:
192 c1 = jcMEDDARK;
193 c2 = jcMEDDARK;
194 c3 = jcLIGHT;
195 c4 = jcLIGHT;
196 break;
197
198 case FR_WIN:
199 default:
200 c1 = jcMEDLT;
201 c2 = jcLIGHT;
202 c3 = jcMEDDARK;
203 c4 = jcDARK;
204 break;
205 }
206
207 if(c1) c1 = scheme[*c1];
208 if(c2) c2 = scheme[*c2];
209 if(c3) c3 = scheme[*c3];
210 if(c4) c4 = scheme[*c4];
211 switch (style)
212 {
213 case FR_RED:
214 c1 = 0xE4;
215 c2 = 0xEC;
216 c3 = 0xE4;
217 c4 = 0xEC;
218 break;
219 case FR_GREEN:
220 c1 = 0xE2;
221 c2 = 0xEA;
222 c3 = 0xE2;
223 c4 = 0xEA;
224 break;
225 }
226 if(c1)
227 {
228 hline(dest, vbound(x,0,dest->w-1), vbound(y,0,dest->h-1) , vbound(x+w-2, 0,dest->w-1), *c1);
229 vline(dest, vbound(x,0,dest->w-1), vbound(y+1,0,dest->h-1), vbound(y+h-2, 0, dest->h-1), *c1);
230 }
231 if(c2)
232 {
233 hline(dest, vbound(x+1,0,dest->w-1), vbound(y+1,0,dest->h-1), vbound(x+w-3,0,dest->w-1), *c2);
234 vline(dest, vbound(x+1,0,dest->w-1), vbound(y+2,0,dest->h-1), vbound(y+h-3,0,dest->h-1), *c2);
235 }
236 if(c3)
237 {
238 hline(dest, vbound(x+1,0,dest->w-1), vbound(y+h-2,0,dest->h-1), vbound(x+w-2,0,dest->w-1), *c3);
239 vline(dest, vbound(x+w-2,0,dest->w-1), vbound(y+1,0,dest->h-1), vbound(y+h-3,0,dest->h-1), *c3);
240 }
241 if(c4)
242 {
243
244 hline(dest, vbound(x,0,dest->w-1), vbound(y+h-1,0,dest->h-1), vbound(x+w-1,0, dest->w-1), *c4);
245 vline(dest, vbound(x+w-1,0,dest->w-1), vbound(y,0,dest->h-1), vbound(y+h-2,0,dest->h-1), *c4);
246 }
247 }
248 void jwin_draw_frag_frame(BITMAP* dest, int x1, int y1, int w, int h, int fw, int fh, int style)
249 {
250 int c1,c2,c3,c4;
251
252 switch(style)
253 {
254 case FR_BOX:
255 c1 = jcLIGHT;
256 c2 = jcMEDLT;
257 c3 = jcMEDDARK;
258 c4 = jcDARK;
259 break;
260
261 case FR_INV:
262 c1 = jcDARK;
263 c2 = jcMEDDARK;
264 c3 = jcMEDLT;
265 c4 = jcLIGHT;
266 break;
267
268 case FR_DEEP:
269 c1 = jcMEDDARK;
270 c2 = jcDARK;
271 c3 = jcMEDLT;
272 c4 = jcLIGHT;
273 break;
274
275 case FR_DARK:
276 c1 = jcDARK;
277 c2 = jcMEDDARK;
278 c3 = jcMEDDARK;
279 c4 = jcDARK;
280 break;
281
282 case FR_ETCHED:
283 c1 = jcMEDDARK;
284 c2 = jcLIGHT;
285 c3 = jcMEDDARK;
286 c4 = jcLIGHT;
287 break;
288
289 case FR_MEDDARK:
290 c1 = jcMEDDARK;
291 c2 = jcBOX;
292 c3 = jcBOX;
293 c4 = jcMEDDARK;
294 break;
295
296 case FR_WIN:
297 default:
298 c1 = jcMEDLT;
299 c2 = jcLIGHT;
300 c3 = jcMEDDARK;
301 c4 = jcDARK;
302 break;
303 }
304
305 int xc = x1+fw-1;
306 int yc = y1+fh-1;
307 int x2 = x1+w-1;
308 int y2 = y1+h-1;
309
310 rectfill(dest, x1, y1, x2, yc, vc(0));
311 rectfill(dest, x1, yc, xc, y2, vc(0));
312
313 hline(dest, x1-2, y1-2, x2+2, scheme[c1]);
314 hline(dest, x1-1, y1-1, x2+1, scheme[c2]);
315
316 vline(dest, x1-2, y1-2, y2+2, scheme[c1]);
317 vline(dest, x1-1, y1-1, y2+1, scheme[c2]);
318
319 hline(dest, x1-2, y2+2, xc+2, scheme[c3]);
320 hline(dest, x1-1, y2+1, xc+1, scheme[c4]);
321
322 vline(dest, x2+2, y1-2, yc+2, scheme[c3]);
323 vline(dest, x2+1, y1-1, yc+1, scheme[c4]);
324
325 hline(dest, xc+2, yc+2, x2+2, scheme[c3]);
326 hline(dest, xc+1, yc+1, x2+1, scheme[c4]);
327
328 vline(dest, xc+2, yc+2, y2+2, scheme[c3]);
329 vline(dest, xc+1, yc+1, y2+1, scheme[c4]);
330 }
331 void jwin_draw_minimap_frame(BITMAP *dest,int x,int y,int w,int h,int scrsz,int style)
332 {
333 jwin_draw_frag_frame(dest,x,y,w,h,scrsz*8,scrsz*8,style);
334 }
335
336 /* jwin_draw_win:
337 * Draws a window -- a box with a frame.
338 */
339 void jwin_draw_win(BITMAP *dest,int32_t x,int32_t y,int32_t w,int32_t h,int32_t frame)
340 {
341 rectfill(dest,zc_max(x,0),zc_max(y,0),zc_min(x+w-1, dest->w-1),zc_min(y+h-1, dest->h-1),scheme[jcBOX]);
342 jwin_draw_frame(dest, x, y, w, h, frame);
343 }
344
345 /* jwin_draw_button:
346 * Helper function for buttons.
347 * Draws a box with a frame that depends on "state":
348 * 0: normal border (slightly different than window border)
349 * 1: inverted border
350 * 2: dark border
351 * 3: medium dark border
352 */
353 void jwin_draw_button(BITMAP *dest,int32_t x,int32_t y,int32_t w,int32_t h,int32_t state,int32_t type)
354 {
355 int32_t frame = FR_BOX;
356
357 if(type==1)
358 {
359 frame=FR_WIN;
360 }
361
362 switch(state)
363 {
364 case 1:
365 frame = FR_INV;
366 break;
367
368 case 2:
369 frame = FR_DARK;
370 break;
371
372 case 3:
373 frame = FR_MEDDARK;
374 break;
375 }
376
377 jwin_draw_win(dest, x, y, w, h, frame);
378 }
379
380 /* mix_value:
381 * Returns a mix of the values c1 and c2 with pos==0 being c1,
382 * pos==max being c2, pos==max/2 being half way between c1 and c2, etc.
383 */
384 int32_t mix_value(int32_t c1,int32_t c2,int32_t pos,int32_t max)
385 {
386 if(max<=0)
387 return c1;
388
389 return (c2 - c1) * pos / max + c1;
390 }
391
392 /* mix_color:
393 * Returns a mix of the colors c1 and c2 with pos==0 being c1,
394 * pos==max being c2, pos==max/2 being half way between c1 and c2, etc.
395 *
396 static int32_t mix_color(int32_t c1,int32_t c2,int32_t pos,int32_t max)
397 {
398 int32_t c;
399
400 if(bitmap_color_depth(screen) == 8)
401 c = mix_value(c1, c2, pos, max);
402 else
403 {
404 int32_t r = mix_value(getr(c1), getr(c2), pos, max);
405 int32_t g = mix_value(getg(c1), getg(c2), pos, max);
406 int32_t b = mix_value(getb(c1), getb(c2), pos, max);
407 c = makecol(r,g,b);
408 }
409
410 return c;
411 }
412 */
413
414 char *shorten_string(char *dest, char const* src, FONT *usefont, int32_t maxchars, int32_t maxwidth)
415 {
416 strncpy(dest,src,maxchars);
417 dest[maxchars-1]='\0';
418 int32_t len=(int32_t)strlen(dest);
419 int32_t width=text_length(usefont, dest);
420 dest[len]=0;
421
422 while(width>maxwidth && len>4)
423 {
424 dest[len-4] = '.';
425 dest[len-3] = '.';
426 dest[len-2] = '.';
427 dest[len-1] = 0;
428 len--;
429 width=text_length(usefont, dest);
430 }
431
432 return dest;
433 }
434
435 void jwin_draw_titlebar(BITMAP *dest, int32_t x, int32_t y, int32_t w, int32_t h, const char *str, bool draw_button, bool helpbtn)
436 {
437 char buf[512];
438 int32_t len = (int32_t)strlen(str);
439 int32_t length = text_length(font,str);
440 int32_t height = text_height(font);
441
442 int32_t tx = x + 2;
443 int32_t ty = y + (h-height)/2;
444 PALETTE temp_pal;
445 get_palette(temp_pal);
446 dither_rect(dest, &temp_pal, x, y, x+w-1, y+h-1,
447 makecol15(temp_pal[scheme[jcTITLEL]].r,
448 temp_pal[scheme[jcTITLEL]].g,
449 temp_pal[scheme[jcTITLEL]].b),
450 makecol15(temp_pal[scheme[jcTITLER]].r,
451 temp_pal[scheme[jcTITLER]].g,
452 temp_pal[scheme[jcTITLER]].b),
453 scheme[jcTITLEL], scheme[jcTITLER]);
454
455
456 if(len>509)
457 len=509;
458
459 strncpy(buf,str,len);
460 buf[len]=0;
461
462 // this part needs work
463
464 if(length>w-20)
465 {
466 while(length>w-20 && len>1)
467 {
468 buf[len-4] = '.';
469 buf[len-3] = '.';
470 buf[len-2] = '.';
471 buf[len-1] = 0;
472 len--;
473 length = text_length(font,buf);
474 }
475 }
476
477 textout_ex(dest,font,buf,tx,ty,scheme[jcTITLEFG],-1);
478
479 if(draw_button)
480 {
481 draw_x_button(dest, x + w - 18, y+2, 0);
482 }
483
484 if(helpbtn)
485 {
486 draw_question_button(dest, x + w - (draw_button ? 36 : 18), y+2, 0);
487 }
488
489 }
490
491 void draw_question_button(BITMAP* dest, int32_t x, int32_t y, int32_t state)
492 {
493 int32_t c = scheme[jcBOXFG];
494
495 jwin_draw_button(dest,x,y,16,14,state,0);
496 x += 4 + (state?1:0);
497 y += 3 + (state?1:0);
498
499 line(dest, x+2, y+0, x+5, y+0, c);
500 line(dest, x+1, y+1, x+2, y+1, c);
501 line(dest, x+5, y+1, x+6, y+1, c);
502 line(dest, x+4, y+2, x+5, y+2, c);
503 line(dest, x+3, y+3, x+4, y+3, c);
504 line(dest, x+3, y+4, x+4, y+4, c);
505 line(dest, x+3, y+6, x+4, y+6, c);
506 line(dest, x+3, y+7, x+4, y+7, c);
507 }
508
509 void draw_x_button(BITMAP *dest, int32_t x, int32_t y, int32_t state)
510 {
511 int32_t c = scheme[jcBOXFG];
512
513 jwin_draw_button(dest,x,y,16,14,state,0);
514 x += 4 + (state?1:0);
515 y += 3 + (state?1:0);
516
517 line(dest,x, y, x+6,y+6,c);
518 line(dest,x+1,y, x+7,y+6,c);
519 line(dest,x, y+6,x+6,y, c);
520 line(dest,x+1,y+6,x+7,y, c);
521 }
522
523 void draw_arrow(BITMAP *dest, int c, int x, int y, int h, bool up, bool center)
524 {
525 if(!center)
526 x += h-1;
527 for(int i = 0; i<h; i++)
528 hline(dest, x-(up?i:h-i-1), y+i, x+(up?i:h-i-1), c);
529 }
530 void draw_arrow_horz(BITMAP *dest, int c, int x, int y, int w, bool left, bool center)
531 {
532 if(!center)
533 y += w-1;
534 for(int i = 0; i<w; i++)
535 vline(dest, x+i, y-(left?i:w-i-1), y+(left?i:w-i-1), c);
536 }
537 void draw_arrow_button(BITMAP *dest, int32_t x, int32_t y, int32_t w, int32_t h, int32_t up, int32_t state)
538 {
539 int32_t c = scheme[jcDARK];
540 int32_t ah = zc_min(h/3, 5);
541 int32_t i = 0;
542
543 jwin_draw_button(dest,x,y,w,h,state,1);
544 x += w/2 - (state?0:1);
545 y += (h-ah)/2 + (state?1:0);
546
547 for(; i<ah; i++)
548 {
549 hline(dest, x-(up?i:ah-i-1), y+i, x+(up?i:ah-i-1), c);
550 }
551 }
552
553 void draw_arrow_button_horiz(BITMAP *dest, int32_t x, int32_t y, int32_t w, int32_t h, int32_t up, int32_t state)
554 {
555 int32_t c = scheme[jcDARK];
556 int32_t aw = zc_min(w/3, 5);
557 int32_t i = 0;
558
559 jwin_draw_button(dest,x,y,w,h,state,1);
560 y += h/2 - (state?0:1);
561 x += (w-aw)/2 + (state?1:0);
562
563 for(; i<aw; i++)
564 {
565 vline(dest, x+i,y-(up?i:aw-i-1), y+(up?i:aw-i-1), c);
566 }
567 }
568
569 int32_t mouse_in_rect(int32_t x,int32_t y,int32_t w,int32_t h)
570 {
571 return ((gui_mouse_x() >= x) && (gui_mouse_y() >= y) &&
572 (gui_mouse_x() < x + w) && (gui_mouse_y() < y + h));
573 }
574
575 static int32_t jwin_do_x_button(BITMAP *dest, int32_t x, int32_t y)
576 {
577 int32_t down=0, last_draw = 0;
578
579 while(gui_mouse_b())
580 {
581 down = mouse_in_rect(x,y,16,14);
582
583 if(down!=last_draw)
584 {
585 draw_x_button(dest,x,y,down);
586 last_draw = down;
587 }
588
589 /* let other objects continue to animate */
590 broadcast_dialog_message(MSG_IDLE, 0);
591 rest(1);
592 }
593
594 if(down)
595 {
596 draw_x_button(dest,x,y,0);
597 }
598
599 return down;
600 }
601
602 /* dotted_rect:
603 * Draws a dotted rectangle, for showing an object has the input focus.
604 */
605 void dotted_rect(BITMAP *dest, int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t fg, int32_t bg)
606 {
607 int32_t x = ((x1+y1) & 1) ? 1 : 0;
608 int32_t c;
609
610 //acquire the bitmap ourselves, because locking a surface within each call is *SLOW AS BALLS* -DD
611 acquire_bitmap(dest);
612
613 for(c=x1; c<=x2; c++)
614 {
615 putpixel(dest, c, y1, (((c+y1) & 1) == x) ? fg : bg);
616 putpixel(dest, c, y2, (((c+y2) & 1) == x) ? fg : bg);
617 }
618
619 for(c=y1+1; c<y2; c++)
620 {
621 putpixel(dest, x1, c, (((c+x1) & 1) == x) ? fg : bg);
622 putpixel(dest, x2, c, (((c+x2) & 1) == x) ? fg : bg);
623 }
624
625 release_bitmap(dest);
626
627 }
628
629 static void _dotted_rect(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t fg, int32_t bg)
630 {
631 dotted_rect(screen, x1, y1, x2, y2, fg, bg);
632 }
633
634 static bool no_hline = false;
635 /* gui_textout_ln:
636 * Wrapper function for drawing text to the screen, which interprets the
637 * & character as an underbar for displaying keyboard shortcuts. Returns
638 * the width of the output string in pixels.
639 *
640 * Handles '\n' characters.
641 */
642 4 int32_t gui_textout_ln(BITMAP *bmp, FONT *f, unsigned const char *s, int32_t x, int32_t y, int32_t color, int32_t bg, int32_t pos)
643 {
644 char tmp[1024];
645 4 int32_t c = 0;
646 int32_t len;
647 4 int32_t pix_len = 0;
648 4 int32_t max_len = 0;
649 int32_t hline_pos;
650 4 int32_t xx = x;
651 4 bool is_scr = bmp == screen;
652
653
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 4 times.
14 while(s[c])
654 {
655 10 len = 0;
656 10 hline_pos = -1;
657
658
4/4
✓ Branch 0 taken 532 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 532 times.
536 for(; (s[c]) && (len<(int32_t)(sizeof(tmp)-1)); c++)
659 {
660
2/2
✓ Branch 0 taken 526 times.
✓ Branch 1 taken 6 times.
532 if(s[c] == '\n')
661 {
662 6 c++;
663 6 break;
664 }
665
2/4
✓ Branch 0 taken 526 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 526 times.
✗ Branch 3 not taken.
526 else if(!no_hline && s[c] == '&')
666 {
667 if(s[c+1] != '&')
668 hline_pos = len;
669 else
670 {
671 tmp[len++] = '&';
672 c++;
673 }
674 }
675 else
676 526 tmp[len++] = s[c];
677 526 }
678
679 10 tmp[len] = 0;
680 10 pix_len = text_length(f, tmp);
681
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 8 times.
10 if (pix_len > max_len) max_len = pix_len;
682 10 x = xx;
683
684
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if(pos==1) //center
685 {
686 x -= pix_len / 2;
687 }
688
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 else if(pos==2) //right
689 {
690 x -= pix_len;
691 }
692
693
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if(bmp)
694 {
695 10 textout_ex(bmp, f, tmp, x, y, color,bg);
696
697
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 if(hline_pos >= 0)
698 {
699 int32_t i;
700 i = tmp[hline_pos];
701 tmp[hline_pos] = 0;
702 hline_pos = text_length(f, tmp);
703 tmp[0] = i;
704 tmp[1] = 0;
705 i = text_length(f, tmp);
706 hline(bmp, x+hline_pos, y+text_height(f)-gui_font_baseline, x+hline_pos+i-1, color);
707 }
708 10 }
709
710 10 y += text_height(f);
711 }
712 4 return max_len;
713 }
714
715 4 int32_t gui_textout_ln(BITMAP *bmp, unsigned const char *s, int32_t x, int32_t y, int32_t color, int32_t bg, int32_t pos)
716 {
717 4 return gui_textout_ln(bmp, font, s, x, y, color, bg, pos);
718 }
719
720 int32_t gui_text_width(FONT *f, const char *s)
721 {
722 return gui_textout_ln(NULL, f, (uint8_t*)s, 0, 0, 0, 0, 0);
723 }
724
725 4 int32_t count_newline(uint8_t *s)
726 {
727 4 int32_t cnt = 0;
728
2/2
✓ Branch 0 taken 532 times.
✓ Branch 1 taken 4 times.
536 for(int32_t q = 0; s[q] != 0; ++q)
729 {
730
2/2
✓ Branch 0 taken 526 times.
✓ Branch 1 taken 6 times.
532 if(s[q] == '\n') ++cnt;
731 532 }
732 4 return cnt;
733 }
734
735 4 int32_t gui_textheight(FONT* f, uint8_t *s)
736 {
737 4 return text_height(f) * (count_newline(s) + 1);
738 }
739
740 4 int32_t gui_textheight(uint8_t* s)
741 {
742 4 return gui_textheight(font, s);
743 }
744
745 /* typedef for the listbox callback functions */
746 typedef char *(*getfuncptr)(int32_t, int32_t *);
747
748 /* event handler that closes a dialog */
749 int32_t close_dlg()
750 {
751 return D_CLOSE;
752 }
753
754 int32_t jwin_frame_proc(int32_t msg, DIALOG *d, int32_t c)
755 {
756 //these are here to bypass compiler warnings about unused arguments
757 c=c;
758
759 if(msg == MSG_DRAW)
760 {
761 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, d->d1);
762 }
763
764 return D_O_K;
765 }
766
767 int32_t jwin_guitest_proc(int32_t msg, DIALOG *d, int32_t c)
768 {
769 //these are here to bypass compiler warnings about unused arguments
770 c=c;
771
772 if(msg == MSG_DRAW)
773 {
774 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, d->d1);
775 }
776
777 return D_O_K;
778 }
779
780 /* jwin_win_proc:
781 * Draws a box with a frame. Use dp for a title string. If dp is NULL,
782 * it won't draw a title bar. If the D_EXIT flag is set, it will also
783 * draw an "X" button on the title bar that can be used to close the
784 * dialog.
785 * If d->dp3 is non-null, it will be read as a help text string, and
786 * a ? button will be drawn, that upon clicking will display the helptext.
787 */
788 int32_t jwin_win_proc(int32_t msg, DIALOG *d, int32_t c)
789 {
790 //these are here to bypass compiler warnings about unused arguments
791 c=c;
792
793 rest(1);
794 static bool skipredraw = false;
795
796 switch(msg)
797 {
798 case MSG_DRAW:
799 if(skipredraw)
800 {
801 skipredraw = false;
802 break;
803 }
804 jwin_draw_win(screen, d->x, d->y, d->w, d->h, FR_WIN);
805
806 if(d->dp)
807 {
808 FONT *oldfont = font;
809
810 if(d->dp2)
811 {
812 font = (FONT*)d->dp2;
813 }
814
815 jwin_draw_titlebar(screen, d->x+3, d->y+3, d->w-6, 18, (char*)d->dp, d->flags & D_EXIT, d->dp3!=NULL);
816 font = oldfont;
817 }
818 break;
819
820 case MSG_WANTFOCUS:
821 if(gui_mouse_b())
822 return D_WANTFOCUS|D_REDRAW;
823 else return D_O_K;
824 case MSG_GOTFOCUS:
825 case MSG_LOSTFOCUS:
826 skipredraw = true;
827 return D_O_K;
828
829 case MSG_CLICK:
830 {
831 if((d->flags & D_EXIT) && mouse_in_rect(d->x+d->w-21, d->y+5, 16, 14))
832 {
833 if(jwin_do_x_button(screen, d->x+d->w-21, d->y+5))
834 {
835 GUI_EVENT(d, geCLOSE);
836 return D_CLOSE;
837 }
838 }
839 if(char const* helpstr = (char const*)d->dp3)
840 {
841 if(mouse_in_rect(d->x+d->w-((d->flags&D_EXIT)?39:21), d->y+5, 16, 14))
842 {
843 broadcast_dialog_message(MSG_DRAW,0);
844 InfoDialog("Info", helpstr).show();
845 }
846 }
847 }
848 break;
849 }
850
851 return D_O_K;
852 }
853
854 /* jwin_text_proc:
855 * Simple dialog procedure: draws the text string which is pointed to by dp.
856 *
857 * Handles '\n' characters.
858 */
859 4 int32_t jwin_text_proc(int32_t msg, DIALOG *d, int32_t)
860 {
861 ASSERT(d);
862
3/6
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
4 static BITMAP *dummy=create_bitmap_ex(8, 1, 1);
863
864
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 switch(msg)
865 {
866 case MSG_START:
867 {
868 4 FONT *oldfont = font;
869
870
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if(d->dp2)
871 {
872 4 font = (FONT*)d->dp2;
873 4 }
874
875 4 d->w=gui_textout_ln(dummy, (uint8_t *)d->dp, 0, 0, scheme[jcMEDDARK], -1, 0);
876 4 d->h=gui_textheight((uint8_t *)d->dp);
877
878 4 font = oldfont;
879 4 break;
880 }
881 case MSG_DRAW:
882 {
883 FONT *oldfont = font;
884
885 if(d->dp2)
886 {
887 font = (FONT*)d->dp2;
888 }
889
890 if(d->flags & D_DISABLED)
891 {
892 gui_textout_ln(screen, (uint8_t*)d->dp, d->x+1, d->y+1, scheme[jcLIGHT], scheme[jcBOX], 0);
893 d->w=gui_textout_ln(screen, (uint8_t*)d->dp, d->x, d->y, scheme[jcDISABLED_FG], -1, 0);
894 }
895 else
896 {
897 d->w=gui_textout_ln(screen, (uint8_t*)d->dp, d->x, d->y, scheme[jcBOXFG], scheme[jcBOX], 0);
898 }
899
900 font = oldfont;
901 break;
902 }
903 }
904
905 4 return D_O_K;
906 }
907
908 int32_t jwin_ctext_proc(int32_t msg, DIALOG *d, int32_t)
909 {
910 ASSERT(d);
911 static BITMAP *dummy=create_bitmap_ex(8, 320, 240);
912
913 switch(msg)
914 {
915 case MSG_START:
916 d->w=gui_textout_ln(dummy, (uint8_t *)d->dp, 0, 0, scheme[jcMEDDARK], -1, 0);
917 break;
918
919 case MSG_DRAW:
920 FONT *oldfont = font;
921
922 if(d->dp2)
923 {
924 font = (FONT*)d->dp2;
925 }
926
927 if(d->flags & D_DISABLED)
928 {
929 gui_textout_ln(screen, (uint8_t*)d->dp, d->x+1, d->y+1, scheme[jcLIGHT], scheme[jcBOX], 1);
930 gui_textout_ln(screen, (uint8_t*)d->dp, d->x, d->y, scheme[jcDISABLED_FG], -1, 1);
931 }
932 else
933 {
934 gui_textout_ln(screen, (uint8_t*)d->dp, d->x, d->y, scheme[jcBOXFG], scheme[jcBOX], 1);
935 }
936
937 font = oldfont;
938 break;
939 }
940
941 return D_O_K;
942 }
943
944 int32_t jwin_rtext_proc(int32_t msg, DIALOG *d, int32_t)
945 {
946 ASSERT(d);
947 static BITMAP *dummy=create_bitmap_ex(8, 1, 1);
948
949 switch(msg)
950 {
951 case MSG_START:
952 d->w=gui_textout_ln(dummy, (uint8_t *)d->dp, 0, 0, scheme[jcMEDDARK], -1, 2);
953 break;
954
955 case MSG_DRAW:
956 FONT *oldfont = font;
957
958 if(d->dp2)
959 {
960 font = (FONT*)d->dp2;
961 }
962
963 if(d->flags & D_DISABLED)
964 {
965 gui_textout_ln(screen, (uint8_t*)d->dp, d->x+1, d->y+1, scheme[jcLIGHT], scheme[jcBOX], 2);
966 gui_textout_ln(screen, (uint8_t*)d->dp, d->x, d->y, scheme[jcDISABLED_FG], -1, 2);
967 }
968 else
969 {
970 gui_textout_ln(screen, (uint8_t*)d->dp, d->x, d->y, scheme[jcBOXFG], scheme[jcBOX], 2);
971 }
972
973 font = oldfont;
974 break;
975 }
976
977 return D_O_K;
978 }
979
980 int32_t d_ctext2_proc(int32_t msg, DIALOG *d, int32_t c)
981 {
982 auto ret = d_ctext_proc(msg, d, c);
983 return ret;
984 }
985
986 int32_t new_text_proc(int32_t msg, DIALOG *d, int32_t c)
987 {
988 BITMAP* oldscreen = screen;
989 if(msg==MSG_DRAW)
990 {
991 if(d->flags & D_HIDDEN) return D_O_K;
992 screen = create_bitmap_ex(8,oldscreen->w,oldscreen->h);
993 clear_bitmap(screen);
994 set_clip_rect(screen, d->x, d->y, d->x+d->w-1, d->y+d->h-1);
995 }
996 int32_t ret = D_O_K;
997 int32_t w = d->w, h = d->h, x = d->x, y = d->y;
998 if(d->d2) no_hline = true;
999 switch(d->d1)
1000 {
1001 case 0:
1002 ret = jwin_text_proc(msg, d, c);
1003 break;
1004 case 1:
1005 d->x += d->w/2;
1006 ret = jwin_ctext_proc(msg, d, c);
1007 break;
1008 case 2:
1009 d->x += d->w - 1;
1010 ret = jwin_rtext_proc(msg, d, c);
1011 break;
1012 }
1013 no_hline = false;
1014 d->w = w;
1015 d->h = h;
1016 d->x = x;
1017 d->y = y;
1018 if(msg==MSG_DRAW)
1019 {
1020 masked_blit(screen, oldscreen, d->x, d->y, d->x, d->y, d->w, d->h);
1021 destroy_bitmap(screen);
1022 screen = oldscreen;
1023 }
1024 if(msg==MSG_WANTFOCUS && gui_mouse_b())
1025 ret |= D_WANTFOCUS|D_REDRAW;
1026 return ret;
1027 }
1028
1029 /* draw_text_button:
1030 * Helper for jwin_button_proc.
1031 */
1032 void jwin_draw_text_button(BITMAP *dest, int32_t x, int32_t y, int32_t w, int32_t h, const char *str, int32_t flags, bool show_dotted_rect)
1033 {
1034 int32_t g = (flags & D_SELECTED) ? 1 : 0;
1035
1036 if(flags & D_SELECTED)
1037 {
1038 jwin_draw_button(dest, x, y, w, h, 2, 0);
1039 flags &= ~D_DISABLED;
1040 }
1041 else if(!(flags & D_GOTFOCUS))
1042 jwin_draw_button(dest, x, y, w, h, 0, 0);
1043 else
1044 {
1045 rect(dest, x, y, x+w-1, y+h-1, scheme[jcDARK]);
1046 jwin_draw_button(dest, x+1, y+1, w-2, h-2, 0, 0);
1047 }
1048
1049 bool drawstring = true;
1050 if(str[1]==0 && byte(str[0]) >= 0x80)
1051 {
1052 drawstring = false;
1053 int col = jwin_pal[(flags & D_DISABLED) ? jcLIGHT : jcBOXFG];
1054 int aw = w/4, ah = h/4;
1055 int woff = (aw/2)+1, hoff = (ah/2)+1;
1056 int x1 = x+w/2, x2 = x+(w-aw)/2;
1057 int y1 = y+(h-aw)/2, y2 = y+h/2;
1058 switch(byte(str[0]))
1059 {
1060 case 0x88:
1061 draw_arrow(dest, col, x1, y1, ah, true, true);
1062 break;
1063 case 0x89:
1064 draw_arrow(dest, col, x1, y1, ah, false, true);
1065 break;
1066 case 0x8A:
1067 draw_arrow_horz(dest, col, x2, y2, aw, true, true);
1068 break;
1069 case 0x8B:
1070 draw_arrow_horz(dest, col, x2, y2, aw, false, true);
1071 break;
1072 case 0x98:
1073 draw_arrow(dest, col, x1, y1-hoff, ah, false, true);
1074 draw_arrow(dest, col, x1, y1+hoff, ah, true, true);
1075 break;
1076 case 0x99:
1077 draw_arrow(dest, col, x1, y1-hoff, ah, true, true);
1078 draw_arrow(dest, col, x1, y1+hoff, ah, false, true);
1079 break;
1080 case 0x9A:
1081 draw_arrow_horz(dest, col, x2-woff, y2, aw, false, true);
1082 draw_arrow_horz(dest, col, x2+woff, y2, aw, true, true);
1083 break;
1084 case 0x9B:
1085 draw_arrow_horz(dest, col, x2-woff, y2, aw, true, true);
1086 draw_arrow_horz(dest, col, x2+woff, y2, aw, false, true);
1087 break;
1088 default: drawstring = true;
1089 }
1090 }
1091 if(drawstring)
1092 {
1093 if(!(flags & D_DISABLED))
1094 gui_textout_ex(dest, str, x+w/2+g, y+(h-text_height(font))/2+g, scheme[jcBOXFG], -1, TRUE);
1095 else
1096 {
1097 gui_textout_ex(dest, str, x+w/2+1,y+(h-text_height(font))/2+1, scheme[jcLIGHT], -1, TRUE);
1098 gui_textout_ex(dest, str, x+w/2, y+(h-text_height(font))/2, scheme[jcDISABLED_FG], -1, TRUE);
1099 }
1100 }
1101
1102 if(show_dotted_rect&&(flags & D_GOTFOCUS))
1103 dotted_rect(dest, x+4, y+4, x+w-5, y+h-5, scheme[jcDARK], scheme[jcBOX]);
1104 }
1105
1106 int icon_proportion(int icon,int s1,int s2)
1107 {
1108 int sz = round(sqrt(zc_min(s1,s2))*1.25);
1109 switch(icon)
1110 {
1111 case BTNICON_STOPSQUARE:
1112 sz += 4;
1113 break;
1114 case BTNICON_PLUS:
1115 case BTNICON_MINUS:
1116 sz += 4;
1117 break;
1118 }
1119 return sz;
1120 }
1121 void jwin_draw_icon_button(BITMAP *dest, int32_t x, int32_t y, int32_t w, int32_t h, int icon, int32_t flags, bool show_dotted_rect)
1122 {
1123 int32_t g = (flags & D_SELECTED) ? 1 : 0;
1124
1125 if(flags & D_SELECTED)
1126 jwin_draw_button(dest, x, y, w, h, 2, 0);
1127 else if(!(flags & D_GOTFOCUS))
1128 jwin_draw_button(dest, x, y, w, h, 0, 0);
1129 else
1130 {
1131 rect(dest, x, y, x+w-1, y+h-1, scheme[jcDARK]);
1132 jwin_draw_button(dest, x+1, y+1, w-2, h-2, 0, 0);
1133 }
1134
1135 int col = jwin_pal[(flags & D_DISABLED) ? jcLIGHT : jcBOXFG];
1136 jwin_draw_icon(dest,x+w/2,y+h/2,col,icon,icon_proportion(icon,w,h),true);
1137
1138 if(show_dotted_rect&&(flags & D_GOTFOCUS))
1139 dotted_rect(dest, x+4, y+4, x+w-5, y+h-5, scheme[jcDARK], scheme[jcBOX]);
1140 }
1141 void jwin_draw_icon(BITMAP *dest, int x, int y, int col, int icon, int asz, bool center)
1142 {
1143 jwin_draw_icon(dest,x,y,col,icon,asz,asz,center);
1144 }
1145 void jwin_draw_icon(BITMAP *dest, int x, int y, int col, int icon, int aw, int ah, bool center)
1146 {
1147 int w2 = aw, h2 = ah;
1148 int sz = zc_min(aw,ah);
1149 switch(icon)
1150 {
1151 case BTNICON_ARROW_LEFT2:
1152 case BTNICON_ARROW_RIGHT2:
1153 aw *= 2;
1154 ah = aw*2-1;
1155 break;
1156 case BTNICON_ARROW_LEFT3:
1157 case BTNICON_ARROW_RIGHT3:
1158 aw *= 3;
1159 ah = aw*2-1;
1160 break;
1161 case BTNICON_ARROW_UP:
1162 case BTNICON_ARROW_DOWN:
1163 case BTNICON_CONTRACT_VERT:
1164 case BTNICON_EXPAND_VERT:
1165 aw = ah*2-1;
1166 break;
1167 case BTNICON_ARROW_LEFT:
1168 case BTNICON_ARROW_RIGHT:
1169 case BTNICON_CONTRACT_HORZ:
1170 case BTNICON_EXPAND_HORZ:
1171 ah = aw*2-1;
1172 break;
1173 case BTNICON_STOPSQUARE:
1174 aw = ah = sz;
1175 break;
1176 case BTNICON_PLUS:
1177 if(!(sz%2)) ++sz;
1178 aw = ah = w2 = h2 = sz;
1179 w2 /= 3;
1180 h2 /= 3;
1181 if(!(h2%2)) ++h2;
1182 if(!(w2%2)) ++w2;
1183 break;
1184 case BTNICON_MINUS:
1185 if(!(sz%2)) ++sz;
1186 aw = ah = w2 = h2 = sz;
1187 h2 /= 3;
1188 if(!(h2%2)) ++h2;
1189 break;
1190 }
1191 int woff = (aw/2)+1, hoff = (ah/2)+1;
1192 int cx = center ? (x-aw/2) : x,
1193 cy = center ? (y-ah/2) : y;
1194 switch(icon)
1195 {
1196 case BTNICON_ARROW_UP:
1197 draw_arrow(dest, col, x, cy, ah, true, center);
1198 break;
1199 case BTNICON_ARROW_DOWN:
1200 draw_arrow(dest, col, x, cy, ah, false, center);
1201 break;
1202 case BTNICON_ARROW_LEFT:
1203 draw_arrow_horz(dest, col, cx, y, aw, true, center);
1204 break;
1205 case BTNICON_ARROW_RIGHT:
1206 draw_arrow_horz(dest, col, cx, y, aw, false, center);
1207 break;
1208 case BTNICON_CONTRACT_VERT:
1209 draw_arrow(dest, col, x, cy-hoff, ah, false, center);
1210 draw_arrow(dest, col, x, cy+hoff, ah, true, center);
1211 break;
1212 case BTNICON_EXPAND_VERT:
1213 draw_arrow(dest, col, x, cy-hoff, ah, true, center);
1214 draw_arrow(dest, col, x, cy+hoff, ah, false, center);
1215 break;
1216 case BTNICON_CONTRACT_HORZ:
1217 draw_arrow_horz(dest, col, cx-woff, y, aw, false, center);
1218 draw_arrow_horz(dest, col, cx+woff, y, aw, true, center);
1219 break;
1220 case BTNICON_EXPAND_HORZ:
1221 draw_arrow_horz(dest, col, cx-woff, y, aw, true, center);
1222 draw_arrow_horz(dest, col, cx+woff, y, aw, false, center);
1223 break;
1224 case BTNICON_ARROW_LEFT2:
1225 draw_arrow_horz(dest, col, cx, y, w2, true, center);
1226 draw_arrow_horz(dest, col, cx+w2, y, w2, true, center);
1227 break;
1228 case BTNICON_ARROW_LEFT3:
1229 draw_arrow_horz(dest, col, cx, y, w2, true, center);
1230 draw_arrow_horz(dest, col, cx+w2, y, w2, true, center);
1231 draw_arrow_horz(dest, col, cx+w2*2, y, w2, true, center);
1232 break;
1233 case BTNICON_ARROW_RIGHT2:
1234 draw_arrow_horz(dest, col, cx, y, w2, false, center);
1235 draw_arrow_horz(dest, col, cx+w2, y, w2, false, center);
1236 break;
1237 case BTNICON_ARROW_RIGHT3:
1238 draw_arrow_horz(dest, col, cx, y, w2, false, center);
1239 draw_arrow_horz(dest, col, cx+w2, y, w2, false, center);
1240 draw_arrow_horz(dest, col, cx+w2*2, y, w2, false, center);
1241 break;
1242 case BTNICON_STOPSQUARE:
1243 rectfill(dest, cx, cy, cx+aw-1, cy+ah-1, col);
1244 break;
1245 case BTNICON_MINUS:
1246 rectfill(dest, cx, cy+(ah/2)-(h2/2), cx+aw-1, cy+(ah/2)+(h2/2), col);
1247 break;
1248 case BTNICON_PLUS:
1249 rectfill(dest, cx, cy+(ah/2)-(h2/2), cx+aw-1, cy+(ah/2)+(h2/2), col);
1250 rectfill(dest, cx+(aw/2)-(w2/2), cy, cx+(aw/2)+(w2/2), cy+ah-1, col);
1251 break;
1252 }
1253 }
1254 /* draw_graphics_button:
1255 * Helper for jwin_button_proc.
1256 */
1257 void jwin_draw_graphics_button(BITMAP *dest, int32_t x, int32_t y, int32_t w, int32_t h, BITMAP *bmp, BITMAP *bmp2, int32_t flags, bool show_dotted_rect, bool overlay)
1258 {
1259 int32_t g = (flags & D_SELECTED) ? 1 : 0;
1260
1261 if(flags & D_SELECTED)
1262 jwin_draw_button(dest, x, y, w, h, 2, 0);
1263 else if(!(flags & D_GOTFOCUS))
1264 jwin_draw_button(dest, x, y, w, h, 0, 0);
1265 else
1266 {
1267 rect(dest, x, y, x+w-1, y+h-1, scheme[jcDARK]);
1268 jwin_draw_button(dest, x+1, y+1, w-2, h-2, 0, 0);
1269 }
1270
1271 if(!(flags & D_DISABLED))
1272 {
1273 // gui_textout_ex(dest, str, x+w/2+g, y+h/2-text_height(font)/2+g, scheme[jcBOXFG], -1, TRUE);
1274 if(bmp!=NULL)
1275 {
1276 if(overlay)
1277 {
1278 masked_blit(bmp, dest, 0, 0, x+w/2-bmp->w/2+g, y+h/2-bmp->h/2+g, bmp->h, bmp->w);
1279 }
1280 else
1281 {
1282 blit(bmp, dest, 0, 0, x+w/2-bmp->w/2+g, y+h/2-bmp->h/2+g, bmp->h, bmp->w);
1283 }
1284 }
1285 }
1286 else
1287 {
1288 // gui_textout_ex(dest, str, x+w/2+1,y+h/2-text_height(font)/2+1, scheme[jcLIGHT], -1, TRUE);
1289 // gui_textout_ex(dest, str, x+w/2, y+h/2-text_height(font)/2, scheme[jcMEDDARK], -1, TRUE);
1290 if(bmp2!=NULL)
1291 {
1292 if(overlay)
1293 {
1294 masked_blit(bmp2, dest, 0, 0, x+w/2-bmp2->w/2+g, y+h/2-bmp2->h/2+g, bmp2->h, bmp2->w);
1295 }
1296 else
1297 {
1298 blit(bmp2, dest, 0, 0, x+w/2-bmp2->w/2+g, y+h/2-bmp2->h/2+g, bmp2->h, bmp2->w);
1299 }
1300 }
1301 }
1302
1303 if(show_dotted_rect&&(flags & D_GOTFOCUS))
1304 dotted_rect(dest, x+4, y+4, x+w-5, y+h-5, scheme[jcDARK], scheme[jcBOX]);
1305 }
1306
1307 /* jwin_button_proc:
1308 * A button object (the dp field points to the text string). This object
1309 * can be selected by clicking on it with the mouse or by pressing its
1310 * keyboard shortcut. If the D_EXIT flag is set, selecting it will close
1311 * the dialog, otherwise it will toggle on and off.
1312 */
1313 int32_t jwin_button_proc(int32_t msg, DIALOG *d, int32_t)
1314 {
1315 int32_t down=0;
1316 int32_t selected=(d->flags&D_SELECTED)?1:0;
1317 int32_t disabled=(d->flags&D_DISABLED)?1:0;
1318 int32_t last_draw;
1319
1320 switch(msg)
1321 {
1322 case MSG_DRAW:
1323 {
1324 FONT *oldfont = font;
1325
1326 if(d->dp2)
1327 {
1328 font = (FONT*)d->dp2;
1329 }
1330
1331 jwin_draw_text_button(screen, d->x, d->y, d->w, d->h, (char*)d->dp, d->flags, true);
1332 font = oldfont;
1333 }
1334 break;
1335
1336 case MSG_WANTFOCUS:
1337 return D_WANTFOCUS;
1338
1339 case MSG_KEY:
1340 if(disabled) break;
1341 /* close dialog? */
1342 if(d->flags & D_EXIT)
1343 {
1344 return D_CLOSE;
1345 }
1346 if(d->d2 == 1) //Insta-button
1347 {
1348 GUI_EVENT(d, geCLICK);
1349 break;
1350 }
1351 /* or just toggle */
1352 d->flags ^= D_SELECTED;
1353 GUI_EVENT(d, geCLICK);
1354 object_message(d, MSG_DRAW, 0);
1355 break;
1356
1357 case MSG_CLICK:
1358 {
1359 if(disabled) break;
1360 if(d->d2 == 1) //Insta-button
1361 {
1362 if(mouse_in_rect(d->x, d->y, d->w, d->h))
1363 {
1364 GUI_EVENT(d, geCLICK);
1365 if(d->flags & D_EXIT)
1366 return D_CLOSE;
1367 }
1368 }
1369 else
1370 {
1371 last_draw = 0;
1372
1373 /* track the mouse until it is released */
1374 while(gui_mouse_b())
1375 {
1376 down = mouse_in_rect(d->x, d->y, d->w, d->h);
1377
1378 /* redraw? */
1379 bool should_redraw = false;
1380 if(last_draw != down)
1381 {
1382 if(down != selected)
1383 d->flags |= D_SELECTED;
1384 else
1385 d->flags &= ~D_SELECTED;
1386
1387 object_message(d, MSG_DRAW, 0);
1388 last_draw = down;
1389 should_redraw = true;
1390 }
1391
1392 /* let other objects continue to animate */
1393 int r = broadcast_dialog_message(MSG_IDLE, 0);
1394 if (r & D_REDRAWME) should_redraw = true;
1395
1396 if (should_redraw)
1397 {
1398 update_hw_screen();
1399 }
1400 }
1401
1402 /* redraw in normal state */
1403 if(down)
1404 {
1405 GUI_EVENT(d, geCLICK);
1406 if(d->flags&D_EXIT)
1407 {
1408 d->flags &= ~D_SELECTED;
1409 object_message(d, MSG_DRAW, 0);
1410 }
1411 }
1412
1413 /* should we close the dialog? */
1414 if(down && (d->flags & D_EXIT))
1415 return D_CLOSE;
1416 }
1417 }
1418 break;
1419 }
1420 return D_O_K;
1421 }
1422 int32_t jwin_iconbutton_proc(int32_t msg, DIALOG *d, int32_t)
1423 {
1424 int32_t down=0;
1425 int32_t selected=(d->flags&D_SELECTED)?1:0;
1426 int32_t last_draw;
1427
1428 switch(msg)
1429 {
1430 case MSG_DRAW:
1431 {
1432 jwin_draw_icon_button(screen, d->x, d->y, d->w, d->h, d->d1, d->flags, true);
1433 }
1434 break;
1435
1436 case MSG_WANTFOCUS:
1437 return D_WANTFOCUS;
1438
1439 case MSG_KEY:
1440 /* close dialog? */
1441 if(d->flags & D_EXIT)
1442 {
1443 return D_CLOSE;
1444 }
1445 if(d->d2 == 1) //Insta-button
1446 {
1447 GUI_EVENT(d, geCLICK);
1448 break;
1449 }
1450 /* or just toggle */
1451 d->flags ^= D_SELECTED;
1452 GUI_EVENT(d, geCLICK);
1453 object_message(d, MSG_DRAW, 0);
1454 break;
1455
1456 case MSG_CLICK:
1457 {
1458 if(d->d2 == 1) //Insta-button
1459 {
1460 if(mouse_in_rect(d->x, d->y, d->w, d->h))
1461 {
1462 GUI_EVENT(d, geCLICK);
1463 if(d->flags & D_EXIT)
1464 return D_CLOSE;
1465 }
1466 }
1467 else
1468 {
1469 last_draw = 0;
1470
1471 /* track the mouse until it is released */
1472 while(gui_mouse_b())
1473 {
1474 down = mouse_in_rect(d->x, d->y, d->w, d->h);
1475
1476 /* redraw? */
1477 bool should_redraw = false;
1478 if(last_draw != down)
1479 {
1480 if(down != selected)
1481 d->flags |= D_SELECTED;
1482 else
1483 d->flags &= ~D_SELECTED;
1484
1485 object_message(d, MSG_DRAW, 0);
1486 last_draw = down;
1487 should_redraw = true;
1488 }
1489
1490 /* let other objects continue to animate */
1491 int r = broadcast_dialog_message(MSG_IDLE, 0);
1492 if (r & D_REDRAWME) should_redraw = true;
1493
1494 if (should_redraw)
1495 {
1496 update_hw_screen();
1497 }
1498 }
1499
1500 /* redraw in normal state */
1501 if(down)
1502 {
1503 GUI_EVENT(d, geCLICK);
1504 if(d->flags&D_EXIT)
1505 {
1506 d->flags &= ~D_SELECTED;
1507 object_message(d, MSG_DRAW, 0);
1508 }
1509 }
1510
1511 /* should we close the dialog? */
1512 if(down && (d->flags & D_EXIT))
1513 return D_CLOSE;
1514 }
1515 }
1516 break;
1517 }
1518 return D_O_K;
1519 }
1520 int32_t jwin_infobtn_proc(int32_t msg, DIALOG *d, int32_t)
1521 {
1522 int32_t down=0;
1523 int32_t selected=(d->flags&D_SELECTED)?1:0;
1524 int32_t last_draw;
1525 std::string* str = (std::string*)d->dp;
1526 bool dis = (d->flags & D_DISABLED) || !str || !((*str)[0]) || str->find_first_not_of(" \t")==std::string::npos;
1527 int flags = d->flags | (dis?D_DISABLED:0);
1528 bool show = false;
1529 switch(msg)
1530 {
1531 case MSG_DRAW:
1532 {
1533 FONT *oldfont = font;
1534
1535 if(d->dp2)
1536 font = (FONT*)d->dp2;
1537
1538 jwin_draw_text_button(screen, d->x, d->y, d->w, d->h, "?", flags, true);
1539 font = oldfont;
1540 }
1541 break;
1542
1543 case MSG_WANTFOCUS:
1544 if(dis) break;
1545 return D_WANTFOCUS;
1546
1547 case MSG_KEY:
1548 if(dis) break;
1549 show = true;
1550 break;
1551
1552 case MSG_CLICK:
1553 {
1554 if(dis) break;
1555 if(d->d2 == 1) //Insta-button
1556 {
1557 if(mouse_in_rect(d->x, d->y, d->w, d->h))
1558 {
1559 show = true;
1560 break;
1561 }
1562 }
1563 else
1564 {
1565 last_draw = 0;
1566
1567 /* track the mouse until it is released */
1568 while(gui_mouse_b())
1569 {
1570 down = mouse_in_rect(d->x, d->y, d->w, d->h);
1571
1572 /* redraw? */
1573 bool should_redraw = false;
1574 if(last_draw != down)
1575 {
1576 if(down != selected)
1577 d->flags |= D_SELECTED;
1578 else
1579 d->flags &= ~D_SELECTED;
1580
1581 object_message(d, MSG_DRAW, 0);
1582 last_draw = down;
1583 should_redraw = true;
1584 }
1585
1586 /* let other objects continue to animate */
1587 int r = broadcast_dialog_message(MSG_IDLE, 0);
1588 if (r & D_REDRAWME) should_redraw = true;
1589
1590 if (should_redraw)
1591 {
1592 update_hw_screen();
1593 }
1594 }
1595
1596 /* redraw in normal state */
1597 if(down)
1598 show = true;
1599 }
1600 }
1601 break;
1602 }
1603 if(show)
1604 {
1605 d->flags &= ~D_SELECTED;
1606 object_message(d, MSG_DRAW, 0);
1607 InfoDialog("Info",*str).show();
1608 GUI_EVENT(d, geCLICK);
1609 }
1610 return D_O_K;
1611 }
1612
1613 /* jwin_func_button_proc:
1614 * A button that runs a void() function when clicked.
1615 * dp: Button text
1616 * dp2: Function to run
1617 */
1618 int32_t jwin_func_button_proc(int32_t msg, DIALOG *d, int32_t c)
1619 {
1620 int32_t down=0;
1621 int32_t selected=(d->flags&D_SELECTED)?1:0;
1622 int32_t last_draw;
1623
1624 if(msg==MSG_CLICK || msg==MSG_KEY)
1625 {
1626 last_draw = 0;
1627
1628 /* track the mouse until it is released */
1629 while(gui_mouse_b())
1630 {
1631 down = mouse_in_rect(d->x, d->y, d->w, d->h);
1632
1633 /* redraw? */
1634 bool should_redraw = false;
1635 if(last_draw != down)
1636 {
1637 if(down != selected)
1638 d->flags |= D_SELECTED;
1639 else
1640 d->flags &= ~D_SELECTED;
1641
1642 object_message(d, MSG_DRAW, 0);
1643 last_draw = down;
1644 should_redraw = true;
1645 }
1646
1647 /* let other objects continue to animate */
1648 int r = broadcast_dialog_message(MSG_IDLE, 0);
1649 if (r & D_REDRAWME) should_redraw = true;
1650
1651 if (should_redraw)
1652 {
1653 update_hw_screen();
1654 }
1655 }
1656
1657 /* redraw in normal state */
1658 if(down)
1659 {
1660 if(d->flags&D_EXIT)
1661 {
1662 d->flags &= ~D_SELECTED;
1663 object_message(d, MSG_DRAW, 0);
1664 }
1665 }
1666
1667 /* pop up and call the function */
1668 if(down)
1669 {
1670 d->flags &= ~D_SELECTED;
1671 object_message(d, MSG_DRAW, 0);
1672 typedef void (*funcType)(void);
1673 funcType func=reinterpret_cast<funcType>(d->dp3);
1674 func();
1675 }
1676
1677 return D_O_K;
1678 }
1679
1680 return jwin_button_proc(msg, d, c);
1681 }
1682
1683 /*(int32_t x = atoi(d->dp);
1684 if ( x > 256 )
1685 d->dp = (char*)"255";
1686 elseif (x < 0 ) d->dp = (char*)"0";
1687 */
1688
1689 #ifdef ALLEGRO_MACOSX
1690 static int WORD_FLAG = KB_ALT_FLAG;
1691 static int LINE_FLAG = KB_COMMAND_FLAG;
1692 #else
1693 static int WORD_FLAG = KB_CTRL_FLAG;
1694 static int LINE_FLAG = KB_ALT_FLAG;
1695 #endif
1696
1697 static int classify_char(char c)
1698 {
1699 if (c == ' ' || c == '\t' || c == '\r')
1700 return 0;
1701 if (c == '/')
1702 return 1;
1703 return 2;
1704 }
1705
1706 static void delete_word(char* s, int* cursor)
1707 {
1708 int start = *cursor;
1709 if (start == 0) return;
1710
1711 int i = start - 1;
1712 int first_ch_class = classify_char(s[i]);
1713 while (i >= 0 && s[i])
1714 {
1715 if (classify_char(s[i]) != first_ch_class)
1716 break;
1717 i--;
1718 }
1719
1720 i++;
1721 *cursor = i;
1722
1723 int j = start;
1724 while (s[j])
1725 s[i++] = s[j++];
1726 s[i] = 0;
1727 }
1728
1729 static void delete_line(char* s, int* cursor)
1730 {
1731 int start = *cursor;
1732 if (start == 0) return;
1733
1734 int i = start - 1;
1735 while (i >= 0 && s[i])
1736 {
1737 bool is_newline = s[i] == '\n';
1738 if (is_newline) break;
1739 i--;
1740 }
1741
1742 i++;
1743 *cursor = i;
1744
1745 int j = start;
1746 while (s[j])
1747 s[i++] = s[j++];
1748 s[i] = 0;
1749 }
1750
1751 int32_t jwin_vedit_proc(int32_t msg, DIALOG *d, int32_t c)
1752 {
1753 if(d->flags & D_HIDDEN)
1754 {
1755 switch(msg)
1756 {
1757 case MSG_CHAR: case MSG_UCHAR: case MSG_XCHAR: case MSG_DRAW: case MSG_CLICK: case MSG_DCLICK: case MSG_KEY: case MSG_WANTFOCUS:
1758 return D_O_K;
1759 }
1760 }
1761 if(d->h < 2+((text_height(d->dp2 ? (FONT*)d->dp2 : font)+2)*2))
1762 return jwin_edit_proc(msg, d, c);
1763 static char nullbuf[2];
1764 sprintf(nullbuf, " ");
1765 int32_t f, l, p, w, x, y, fg, bg;
1766 int32_t lastSpace = -1;
1767 char *s;
1768 char buf[2] = {0,0};
1769
1770 if(d->dp==NULL)
1771 {
1772 d->dp=(void *)nullbuf;
1773 }
1774
1775 s = (char*)d->dp;
1776 l = (int32_t)strlen(s);
1777
1778 int32_t cursor_start = d->d2 & 0x0000FFFF;
1779 int32_t cursor_end = int32_t((d->d2 & 0xFFFF0000) >> 16);
1780 // This was previously doing bitshifts on -1. There wasn't enough space so I cannibalized 0xFFFF instead. -Moosh
1781 if (cursor_start == 0xFFFF)
1782 cursor_start = -1;
1783 if (cursor_end == 0xFFFF)
1784 cursor_end = -1;
1785
1786 if(cursor_start > l)
1787 cursor_start = l;
1788 if(cursor_end > l)
1789 cursor_end = l;
1790 auto low_cursor = cursor_start<0 ? cursor_end : (cursor_end<0 ? cursor_start : (zc_min(cursor_start, cursor_end)));
1791 auto high_cursor = zc_max(cursor_start,cursor_end);
1792 bool range_selected = cursor_end > -1;
1793
1794 FONT *oldfont = font;
1795 if(d->dp2)
1796 font = (FONT*)d->dp2;
1797
1798 auto* char_length = font->vtable->char_length;
1799 std::vector<size_t> lines;
1800 x = 0;
1801
1802 y = d->y + 2;
1803 size_t ind = 0;
1804 int32_t yinc = text_height(font)+2;
1805 int32_t maxy = y;
1806 size_t maxlines = 1;
1807 while(maxy+yinc < d->y+d->h-3)
1808 {
1809 maxy += yinc;
1810 ++maxlines;
1811 }
1812 size_t half_width = (maxlines-1)/2;
1813 size_t line_scroll = 0;
1814 size_t focused_line = size_t(-1);
1815 size_t focused_line2 = size_t(-1);
1816 switch(msg)
1817 {
1818 //Only these messages need these calculations, so save processing.
1819 case MSG_DRAW:
1820 case MSG_CLICK:
1821 case MSG_CHAR:
1822 {
1823 for(auto q = 0; q <= l; ++q)
1824 {
1825 char c = s[q] ? s[q] : ' ';
1826 x += char_length(font, c);
1827 if(x > d->w - 6)
1828 {
1829 // Line's too long, break
1830 if(lastSpace >= 0)
1831 {
1832 q = lastSpace+1;
1833 lines.push_back(q);
1834 lastSpace = -1;
1835 }
1836 else
1837 {
1838 lines.push_back(q);
1839 }
1840 x = 0;
1841 --q; //counteract increment
1842 }
1843 else if(c == ' ')
1844 lastSpace = q;
1845 }
1846 if(lines.empty() || lines.back() != l+1)
1847 lines.push_back(l+1);
1848 for(size_t line = 0; line < lines.size(); ++line)
1849 {
1850 if(size_t(range_selected ? cursor_end : cursor_start) < lines[line]) //should ALWAYS execute once
1851 {
1852 focused_line = line;
1853 break;
1854 }
1855 }
1856 if(!range_selected)
1857 {
1858 focused_line2 = -1;
1859 }
1860 else for(size_t line = 0; line < lines.size(); ++line)
1861 {
1862 if(size_t(cursor_start) < lines[line]) //should ALWAYS execute once
1863 {
1864 focused_line2 = line;
1865 break;
1866 }
1867 }
1868 if (focused_line >= lines.size())
1869 focused_line = lines.size() - 1;
1870 if (focused_line2 >= lines.size())
1871 focused_line2 = lines.size() - 1;
1872 if(maxlines >= lines.size() || focused_line <= half_width)
1873 line_scroll = 0;
1874 else if(lines.size()-maxlines+half_width < focused_line)
1875 line_scroll = lines.size()-maxlines+half_width-1;
1876 else
1877 line_scroll = focused_line - half_width;
1878 }
1879 }
1880 font = oldfont; //in case of early return, need to reset here
1881 static bool dclick = false;
1882 switch(msg)
1883 {
1884 case MSG_START:
1885 dclick = false;
1886 cursor_start = (int32_t)strlen((char*)d->dp);
1887 cursor_end = -1;
1888 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
1889 break;
1890
1891 case MSG_DRAW:
1892 {
1893 if(d->dp2)
1894 font = (FONT*)d->dp2;
1895 if(d->flags & D_DISABLED)
1896 {
1897 fg = scheme[jcDISABLED_FG];
1898 bg = scheme[jcDISABLED_BG];
1899 }
1900 else if(d->flags & D_READONLY)
1901 {
1902 fg = scheme[jcALT_TEXTFG];
1903 bg = scheme[jcALT_TEXTBG];
1904 }
1905 else
1906 {
1907 fg = scheme[jcTEXTFG];
1908 bg = scheme[jcTEXTBG];
1909 }
1910
1911 //Fill the BG
1912 rectfill(screen, d->x+2, d->y+2, d->x+d->w-3, d->y+d->h-3, bg);
1913
1914 //Now the text
1915 size_t m = zc_min(line_scroll + maxlines, lines.size());
1916 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, FR_DEEP);
1917 for(size_t line = line_scroll; line < m; ++line, y+=yinc)
1918 {
1919 x = 3;
1920 for(ind = line ? lines[line-1] : 0; ind < lines[line]; ++ind)
1921 {
1922 char c = s[ind] ? s[ind] : ' ';
1923 w = char_length(font, c);
1924 bool focused = range_selected
1925 ? (ind >= low_cursor && ind <= high_cursor)
1926 : (ind == cursor_start);
1927 f = (focused && (d->flags & D_GOTFOCUS));
1928 buf[0] = c;
1929 textout_ex(screen, font, buf, d->x+x, y, f ? bg : fg,f ? fg : bg);
1930 x += w;
1931 }
1932 }
1933
1934 font = oldfont;
1935 break;
1936 }
1937
1938 case MSG_DCLICK:
1939 if ((gui_mouse_b() & 2) != 0)
1940 break;
1941 if (d->flags & (D_DISABLED | D_READONLY))
1942 break;
1943 dclick = true;
1944 break;
1945 case MSG_CLICK:
1946 {
1947 if(d->flags & (D_DISABLED|D_READONLY))
1948 break;
1949 if(d->dp2)
1950 font = (FONT*)d->dp2;
1951
1952 bool found = false;
1953 for(size_t line = line_scroll; line < lines.size() && line < (line_scroll + maxlines); ++line, y+=yinc)
1954 {
1955 if(gui_mouse_y() >= y+yinc)
1956 continue;
1957 x = d->x+3;
1958 for(ind = line ? lines[line-1] : 0; ind < lines[line]; ++ind)
1959 {
1960 x += char_length(font, s[ind]);
1961 if(x >= gui_mouse_x())
1962 {
1963 if(key_shifts&KB_SHIFT_FLAG)
1964 cursor_end = ind;
1965 else
1966 {
1967 cursor_start = ind;
1968 cursor_end = -1;
1969 if (dclick)
1970 cursor_end = cursor_start;
1971 }
1972 found = true;
1973 break;
1974 }
1975 }
1976 break;
1977 }
1978 if(!found)
1979 {
1980 if(key_shifts&KB_SHIFT_FLAG)
1981 cursor_end = l;
1982 else
1983 {
1984 cursor_start = l;
1985 cursor_end = -1;
1986 if (dclick)
1987 cursor_end = cursor_start;
1988 }
1989 }
1990
1991 if (dclick)
1992 {
1993 while (cursor_start > 0 && cursor_start < l)
1994 {
1995 if (s[cursor_start] == ' ')
1996 {
1997 if (cursor_start <= cursor_end)
1998 ++cursor_start;
1999 else
2000 --cursor_start;
2001 break;
2002 }
2003 if (cursor_start <= cursor_end)
2004 --cursor_start;
2005 else
2006 ++cursor_start;
2007 }
2008 while (cursor_end > 0 && cursor_end < l)
2009 {
2010 if (s[cursor_end] == ' ')
2011 {
2012 if (cursor_end >= cursor_start)
2013 --cursor_end;
2014 else
2015 ++cursor_end;
2016 break;
2017 }
2018 if (cursor_end >= cursor_start)
2019 ++cursor_end;
2020 else
2021 --cursor_end;
2022 }
2023 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2024 d->flags |= D_DIRTY;
2025 }
2026 else
2027 {
2028 if (cursor_end == cursor_start) cursor_end = -1;
2029 else d->flags |= D_DIRTY;
2030 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2031 }
2032
2033 object_message(d, MSG_DRAW, 0);
2034 font = oldfont;
2035 dclick = false;
2036 break;
2037 }
2038
2039 case MSG_WANTFOCUS:
2040 case MSG_LOSTFOCUS:
2041 case MSG_KEY:
2042 if(d->flags & (D_DISABLED|D_READONLY))
2043 break;
2044 return D_WANTFOCUS;
2045
2046 case MSG_CHAR:
2047 {
2048 if(d->flags & (D_DISABLED|D_READONLY))
2049 break;
2050 bool shifted = key_shifts & KB_SHIFT_FLAG;
2051 bool ctrl = key_shifts & KB_CTRL_CMD_FLAG;
2052 bool word_modifier = key_shifts & WORD_FLAG;
2053 bool line_modifier = key_shifts & LINE_FLAG;
2054 bool change_cursor = true;
2055 int32_t scursor = cursor_start, ecursor = cursor_end;
2056 char upper_c = c>>8;
2057 char lower_c = c&255;
2058
2059 if(shifted)
2060 {
2061 if(ecursor < 0)
2062 {
2063 ecursor = scursor;
2064 focused_line2 = focused_line;
2065 }
2066 }
2067 if(upper_c == KEY_LEFT)
2068 {
2069 if(shifted)
2070 {
2071 if(ecursor>0)
2072 --ecursor;
2073 }
2074 else
2075 {
2076 ecursor = -1;
2077 if(scursor > 0)
2078 --scursor;
2079 }
2080 }
2081 else if(upper_c == KEY_RIGHT)
2082 {
2083 if(shifted)
2084 {
2085 if(ecursor < l)
2086 ++ecursor;
2087 }
2088 else
2089 {
2090 ecursor = -1;
2091 if(scursor < l)
2092 ++scursor;
2093 }
2094 }
2095 else if(upper_c == KEY_UP || upper_c == KEY_DOWN)
2096 {
2097 if(shifted)
2098 {
2099 size_t line = focused_line2 + (upper_c == KEY_UP ? -1 : 1);
2100 if(!focused_line2 && upper_c == KEY_UP)
2101 ecursor = 0;
2102 else if(line >= lines.size())
2103 ecursor = l;
2104 else
2105 {
2106 if(d->dp2)
2107 font = (FONT*)d->dp2;
2108 x = d->x + 3;
2109 for(ind = focused_line2 ? lines[focused_line2-1] : 0; ind < lines[focused_line2]; ++ind)
2110 {
2111 w = char_length(font, s[ind]);
2112 if(ind < size_t(ecursor))
2113 x += w;
2114 else
2115 {
2116 x += w / 2;
2117 break;
2118 }
2119 }
2120
2121 int32_t tx = d->x+3;
2122 bool done = false;
2123 for(ind = line ? lines[line-1] : 0; ind < lines[line]; ++ind)
2124 {
2125 tx += char_length(font, s[ind] ? s[ind] : ' ');
2126 if(tx < x)
2127 continue;
2128 ecursor = ind;
2129 done = true;
2130 break;
2131 }
2132 font = oldfont;
2133 if(!done)
2134 {
2135 ecursor = (upper_c == KEY_UP) ? 0 : lines[line]-1;
2136 }
2137 }
2138 }
2139 else
2140 {
2141 ecursor = -1;
2142 if(range_selected)
2143 {
2144 focused_line = focused_line2;
2145 scursor = ecursor;
2146 }
2147 size_t line = focused_line + (upper_c == KEY_UP ? -1 : 1);
2148 if(!focused_line && upper_c == KEY_UP)
2149 scursor = 0;
2150 else if(line >= lines.size())
2151 scursor = l;
2152 else
2153 {
2154 if(d->dp2)
2155 font = (FONT*)d->dp2;
2156 x = d->x + 3;
2157 for(ind = focused_line ? lines[focused_line-1] : 0; ind < lines[focused_line]; ++ind)
2158 {
2159 w = char_length(font, s[ind]);
2160 if(ind < size_t(scursor))
2161 x += w;
2162 else
2163 {
2164 x += w / 2;
2165 break;
2166 }
2167 }
2168
2169 int32_t tx = d->x+3;
2170 bool done = false;
2171 for(ind = line ? lines[line-1] : 0; ind < lines[line]; ++ind)
2172 {
2173 tx += char_length(font, s[ind] ? s[ind] : ' ');
2174 if(tx < x)
2175 continue;
2176 scursor = ind;
2177 done = true;
2178 break;
2179 }
2180 font = oldfont;
2181 if(!done)
2182 {
2183 scursor = (upper_c == KEY_UP) ? 0 : lines[line]-1;
2184 }
2185 }
2186 }
2187 }
2188 else if(upper_c == KEY_HOME)
2189 {
2190 if(shifted)
2191 ecursor = 0;
2192 else
2193 {
2194 ecursor = -1;
2195 scursor = 0;
2196 }
2197 }
2198 else if(upper_c == KEY_END)
2199 {
2200 if(shifted)
2201 ecursor = l;
2202 else
2203 {
2204 ecursor = -1;
2205 scursor = l;
2206 }
2207 }
2208 else if(upper_c == KEY_DEL)
2209 {
2210 if(ctrl)
2211 {
2212 s[0] = 0;
2213 scursor = 0;
2214 ecursor = -1;
2215 GUI_EVENT(d, geCHANGE_VALUE);
2216 }
2217 else if(range_selected)
2218 {
2219 ecursor = -1;
2220 scursor = low_cursor;
2221 size_t ind = low_cursor, ind2 = high_cursor+1;
2222 while(ind2 < l && s[ind2])
2223 s[ind++] = s[ind2++];
2224 while(s[ind])
2225 s[ind++] = 0;
2226 GUI_EVENT(d, geCHANGE_VALUE);
2227 }
2228 else if(scursor < l)
2229 {
2230 for(p=scursor; s[p]; p++)
2231 s[p] = s[p+1];
2232 GUI_EVENT(d, geCHANGE_VALUE);
2233 }
2234 }
2235 else if(upper_c == KEY_BACKSPACE)
2236 {
2237 if(line_modifier)
2238 {
2239 delete_line(s, &scursor);
2240 ecursor = -1;
2241 GUI_EVENT(d, geCHANGE_VALUE);
2242 }
2243 else if(word_modifier)
2244 {
2245 delete_word(s, &scursor);
2246 ecursor = -1;
2247 GUI_EVENT(d, geCHANGE_VALUE);
2248 }
2249 else if(range_selected)
2250 {
2251 ecursor = -1;
2252 scursor = low_cursor;
2253 size_t ind = low_cursor, ind2 = high_cursor+1;
2254 while(ind2 < l && s[ind2])
2255 s[ind++] = s[ind2++];
2256 while(s[ind])
2257 s[ind++] = 0;
2258 GUI_EVENT(d, geCHANGE_VALUE);
2259 }
2260 else if(scursor > 0)
2261 {
2262 --scursor;
2263 for(p=scursor; s[p]; p++)
2264 s[p] = s[p+1];
2265 GUI_EVENT(d, geCHANGE_VALUE);
2266 }
2267 }
2268 else if(upper_c == KEY_ENTER)
2269 {
2270 change_cursor = false;
2271 GUI_EVENT(d, geENTER);
2272 if(d->flags & D_EXIT)
2273 {
2274 object_message(d, MSG_DRAW, 0);
2275 return D_CLOSE;
2276 }
2277 else
2278 return D_O_K;
2279 }
2280 else if(upper_c == KEY_TAB)
2281 {
2282 change_cursor = false;
2283 return D_O_K;
2284 }
2285 else if(ctrl && upper_c == KEY_C)
2286 {
2287 change_cursor = false;
2288 std::ostringstream oss;
2289 if(range_selected)
2290 {
2291 for(size_t ind = low_cursor; ind <= high_cursor; ++ind)
2292 {
2293 if(s[ind])
2294 oss << s[ind];
2295 }
2296 }
2297 else
2298 {
2299 if(s[scursor])
2300 oss << s[scursor];
2301 }
2302 set_al_clipboard(oss.str());
2303 }
2304 else if (ctrl && upper_c == KEY_V && clipboard_has_text())
2305 {
2306 std::string cb;
2307 if(get_al_clipboard(cb))
2308 {
2309 int ind = low_cursor, ind2 = high_cursor + 1;
2310 if (range_selected)
2311 {
2312 //Delete selected text
2313 ecursor = -1;
2314 scursor = low_cursor;
2315 while (s[ind2] && ind2 < l)
2316 s[ind++] = s[ind2++];
2317 while (s[ind])
2318 s[ind++] = 0;
2319 l = (int32_t)strlen(s);
2320 }
2321 //Move the text out of the way of the pasting
2322 int paste_len = cb.size();
2323 int paste_start = scursor;
2324 int paste_end = paste_start+paste_len;
2325 ind = strlen(s);
2326 ind2 = ind+paste_len;
2327 while(ind2 > d->d1)
2328 {
2329 --ind;
2330 --ind2;
2331 }
2332 size_t new_l = ind2;
2333 while(ind >= paste_start)
2334 {
2335 if(s[ind] || (ind&&s[ind-1]))
2336 {
2337 s[ind2] = s[ind];
2338 }
2339 --ind2; --ind;
2340 }
2341 for(auto q = 0; q < paste_len && paste_start+q < new_l; ++q)
2342 {
2343 s[paste_start+q] = cb.at(q);
2344 }
2345 s[new_l] = 0;
2346 scursor = paste_start + paste_len;
2347 ecursor = -1;
2348 GUI_EVENT(d, geCHANGE_VALUE);
2349 }
2350 }
2351 else if (ctrl && upper_c == KEY_A)
2352 {
2353 cursor_start = 0;
2354 cursor_end = (int16_t)strlen((char*)d->dp) - 1;
2355 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2356 d->flags |= D_DIRTY;
2357 break;
2358 }
2359 else if(lower_c >= 32 && !ctrl)
2360 {
2361 if(range_selected)
2362 {
2363 //Delete selected text
2364 ecursor = -1;
2365 scursor = low_cursor;
2366 size_t ind = low_cursor, ind2 = high_cursor+1;
2367 while(ind2 < l && s[ind2])
2368 s[ind++] = s[ind2++];
2369 while(s[ind])
2370 s[ind++] = 0;
2371 l = (int32_t)strlen(s);
2372 //Type the character in its' place
2373 //(fallthrough)
2374 }
2375 if(l < d->d1)
2376 {
2377 ecursor = -1;
2378 s[l+1] = 0;
2379 size_t ind = l;
2380 while(ind >= scursor)
2381 {
2382 s[ind+1] = s[ind];
2383 if (!ind) break;
2384 --ind;
2385 }
2386
2387 s[scursor++] = lower_c;
2388
2389 GUI_EVENT(d, geCHANGE_VALUE);
2390 }
2391 }
2392 else
2393 return D_O_K;
2394
2395 if(change_cursor)
2396 {
2397 if (cursor_start != scursor)
2398 d->flags |= D_DIRTY;
2399
2400 cursor_end = ecursor; cursor_start = scursor;
2401 if (cursor_end == cursor_start) cursor_end = -1;
2402 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2403 }
2404
2405 /* if we changed something, better redraw... */
2406 object_message(d, MSG_DRAW, 0);
2407 return D_USED_CHAR;
2408 }
2409 }
2410
2411 return D_O_K;
2412 }
2413
2414 /* jwin_edit_proc:
2415 * An editable text object (the dp field points to the string). When it
2416 * has the input focus (obtained by clicking on it with the mouse), text
2417 * can be typed into this object. The d1 field specifies the maximum
2418 * number of characters that it will accept, and d2 is the text cursor
2419 * position within the string.
2420 */
2421 int32_t jwin_edit_proc(int32_t msg, DIALOG *d, int32_t c)
2422 {
2423 if(d->flags & D_HIDDEN)
2424 {
2425 switch(msg)
2426 {
2427 case MSG_CHAR: case MSG_UCHAR: case MSG_XCHAR: case MSG_DRAW: case MSG_CLICK: case MSG_DCLICK: case MSG_KEY: case MSG_WANTFOCUS:
2428 return D_O_K;
2429 }
2430 }
2431 if(d->h >= 2+((text_height(d->dp2 ? (FONT*)d->dp2 : font)+2)*2))
2432 return jwin_vedit_proc(msg, d, c);
2433 int32_t f, l, p, w, x, y, fg, bg, fg2 = -1, bg2 = -1, fg3, bg3;
2434 int32_t b;
2435 int32_t scroll;
2436 char *s;
2437 char buf[2];
2438 static char nullbuf[2];
2439 sprintf(nullbuf, " ");
2440
2441 if(d->dp==NULL)
2442 {
2443 d->dp=(void *)nullbuf;
2444 }
2445
2446 s = (char*)d->dp;
2447 l = (int32_t)strlen(s);
2448
2449 int32_t cursor_start = d->d2 & 0x0000FFFF;
2450 int32_t cursor_end = int32_t((d->d2 & 0xFFFF0000) >> 16);
2451 // This was previously doing bitshifts on -1. There wasn't enough space so I cannibalized 0xFFFF instead. -Moosh
2452 if (cursor_start == 0xFFFF)
2453 cursor_start = -1;
2454 if (cursor_end == 0xFFFF)
2455 cursor_end = -1;
2456
2457 if(cursor_start > l)
2458 cursor_start = l;
2459 if(cursor_end > l)
2460 cursor_end = l;
2461 auto low_cursor = cursor_start<0 ? cursor_end : (cursor_end<0 ? cursor_start : (zc_min(cursor_start, cursor_end)));
2462 auto high_cursor = zc_max(cursor_start,cursor_end);
2463
2464 /* calculate maximal number of displayable characters */
2465 b = x = 0;
2466
2467 if(cursor_start == l)
2468 {
2469 buf[0] = ' ';
2470 buf[1] = 0;
2471
2472 if(d->dp2)
2473 x = text_length((FONT*)d->dp2, buf);
2474 else
2475 x = text_length(font, buf);
2476 }
2477
2478 buf[1] = 0;
2479
2480 for(p=cursor_start; p>=0; p--)
2481 {
2482 buf[0] = s[p];
2483 b++;
2484
2485 if(d->dp2)
2486 x += text_length((FONT*)d->dp2, buf);
2487 else
2488 x += text_length(font, buf);
2489
2490 if(x > d->w-6)
2491 break;
2492 }
2493
2494 if(x <= d->w-6)
2495 {
2496 b = l;
2497 scroll = FALSE;
2498 }
2499 else
2500 {
2501 b--;
2502 scroll = TRUE;
2503 }
2504
2505 FONT *oldfont = font;
2506 static bool dclick = false;
2507 switch(msg)
2508 {
2509 case MSG_START:
2510 dclick = false;
2511 cursor_start = (int32_t)strlen((char*)d->dp);
2512 cursor_end = -1;
2513 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2514 break;
2515
2516 case MSG_DRAW:
2517 {
2518 if(d->dp2)
2519 {
2520 font = (FONT*)d->dp2;
2521 }
2522 if(d->flags & D_DISABLED)
2523 {
2524 fg2 = scheme[jcLIGHT];
2525 bg2 = scheme[jcDISABLED_BG];
2526 fg = scheme[jcDISABLED_FG];
2527 bg = -1;
2528 fg3 = fg;
2529 bg3 = bg2;
2530 }
2531 else if(d->flags & D_READONLY)
2532 {
2533 fg = scheme[jcALT_TEXTFG];
2534 bg = scheme[jcALT_TEXTBG];
2535 fg3 = fg;
2536 bg3 = bg;
2537 }
2538 else
2539 {
2540 fg = scheme[jcTEXTFG];
2541 bg = scheme[jcTEXTBG];
2542 fg3 = fg;
2543 bg3 = bg;
2544 }
2545
2546 x = 3;
2547 y = (d->h - text_height(font)) / 2 + d->y;
2548
2549 /* first fill in the edges */
2550
2551 rectfill(screen, d->x+2, d->y+2, d->x+d->w-3, d->y+d->h-3, bg3);
2552
2553 vline(screen, d->x+2, d->y+2, d->y+d->h-3, bg3);
2554
2555 /* now the text */
2556
2557 if(scroll)
2558 {
2559 p = cursor_start-b+1;
2560 b = cursor_start;
2561 }
2562 else
2563 p = 0;
2564 for(; p<=b; p++)
2565 {
2566 buf[0] = s[p] ? s[p] : ' ';
2567 w = text_length(font, buf);
2568
2569 if(x+w > d->w)
2570 break;
2571 bool focused = (cursor_end>-1)
2572 ? (p >= low_cursor && p <= high_cursor)
2573 : (p == cursor_start);
2574 f = fg2 < 0 && (focused && (d->flags & D_GOTFOCUS));
2575 if(fg2 > -1)
2576 {
2577 textout_ex(screen, font, buf, d->x+x+1, y+1, fg2, bg2);
2578 }
2579 textout_ex(screen, font, buf, d->x+x, y, f ? bg : fg,f ? fg : bg);
2580 x += w;
2581 }
2582
2583 if(x < d->w-2)
2584 rectfill(screen, d->x+x, y, d->x+d->w-3, y+text_height(font)-1, bg3);
2585
2586 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, FR_DEEP);
2587 font = oldfont;
2588 break;
2589 }
2590
2591 case MSG_DCLICK:
2592 if ((gui_mouse_b() & 2) != 0)
2593 break;
2594 if (d->flags & (D_DISABLED | D_READONLY))
2595 break;
2596 dclick = true;
2597 break;
2598 case MSG_CLICK:
2599 {
2600 if(d->flags & (D_DISABLED|D_READONLY))
2601 break;
2602 x = d->x+3;
2603
2604 if(scroll)
2605 {
2606 p = cursor_start-b+1;
2607 b = cursor_start;
2608 }
2609 else
2610 p = 0;
2611
2612 for(; p<b; p++)
2613 {
2614 buf[0] = s[p];
2615 x += text_length((d->dp2) ? (FONT*)d->dp2 : font, buf);
2616
2617 if(x > gui_mouse_x())
2618 break;
2619 }
2620
2621 if(key_shifts&KB_SHIFT_FLAG)
2622 cursor_end = MID(0, p, l);
2623 else
2624 {
2625 cursor_end = -1;
2626 cursor_start = MID(0, p, l);
2627 if (dclick)
2628 cursor_end = cursor_start;
2629 }
2630
2631 if (dclick)
2632 {
2633 while (cursor_start > 0 && cursor_start < l)
2634 {
2635 if (s[cursor_start] == ' ')
2636 {
2637 if (cursor_start <= cursor_end)
2638 ++cursor_start;
2639 else
2640 --cursor_start;
2641 break;
2642 }
2643 if (cursor_start <= cursor_end)
2644 --cursor_start;
2645 else
2646 ++cursor_start;
2647 }
2648 while (cursor_end > 0 && cursor_end < l)
2649 {
2650 if (s[cursor_end] == ' ')
2651 {
2652 if (cursor_end >= cursor_start)
2653 --cursor_end;
2654 else
2655 ++cursor_end;
2656 break;
2657 }
2658 if (cursor_end >= cursor_start)
2659 ++cursor_end;
2660 else
2661 --cursor_end;
2662 }
2663 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2664 d->flags |= D_DIRTY;
2665 }
2666 else
2667 {
2668 if (cursor_end == cursor_start) cursor_end = -1;
2669 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2670 }
2671 d->flags |= D_DIRTY;
2672 dclick = false;
2673 break;
2674 }
2675
2676 case MSG_WANTFOCUS:
2677 case MSG_LOSTFOCUS:
2678 case MSG_KEY:
2679 if(d->flags & (D_DISABLED|D_READONLY))
2680 break;
2681 return D_WANTFOCUS;
2682
2683 case MSG_CHAR:
2684 {
2685 if(d->flags & (D_DISABLED|D_READONLY))
2686 break;
2687 bool shifted = key_shifts & KB_SHIFT_FLAG;
2688 bool ctrl = key_shifts & KB_CTRL_CMD_FLAG;
2689 bool word_modifier = key_shifts & WORD_FLAG;
2690 bool line_modifier = key_shifts & LINE_FLAG;
2691 bool change_cursor = true;
2692 bool change_value = false;
2693 int scursor = cursor_start, ecursor = cursor_end;
2694 bool range_selected = cursor_end > -1;
2695 auto upper_c = c>>8;
2696 auto lower_c = c&0xFF;
2697
2698 if(shifted)
2699 {
2700 if(ecursor < 0)
2701 ecursor = scursor;
2702 }
2703 if(upper_c == KEY_LEFT)
2704 {
2705 if(shifted)
2706 {
2707 if(ecursor>0)
2708 --ecursor;
2709 }
2710 else
2711 {
2712 ecursor = -1;
2713 if(scursor > 0)
2714 --scursor;
2715 }
2716 }
2717 else if(upper_c == KEY_RIGHT)
2718 {
2719 if(shifted)
2720 {
2721 if(ecursor < l)
2722 ++ecursor;
2723 }
2724 else
2725 {
2726 ecursor = -1;
2727 if(scursor < l)
2728 ++scursor;
2729 }
2730 }
2731 else if(upper_c == KEY_HOME)
2732 {
2733 if(shifted)
2734 ecursor = 0;
2735 else
2736 {
2737 ecursor = -1;
2738 scursor = 0;
2739 }
2740 }
2741 else if(upper_c == KEY_END)
2742 {
2743 if(shifted)
2744 ecursor = l;
2745 else
2746 {
2747 ecursor = -1;
2748 scursor = l;
2749 }
2750 }
2751 else if(upper_c == KEY_DEL)
2752 {
2753 if(ctrl)
2754 {
2755 s[0] = 0;
2756 scursor = 0;
2757 ecursor = -1;
2758 GUI_EVENT(d, geCHANGE_VALUE);
2759 change_value = true;
2760 }
2761 else if(range_selected)
2762 {
2763 ecursor = -1;
2764 scursor = low_cursor;
2765 int ind = low_cursor, ind2 = high_cursor+1;
2766 ind2 = std::min(ind2, d->d1 - 1);
2767 while(s[ind2])
2768 s[ind++] = s[ind2++];
2769 while(s[ind])
2770 s[ind++] = 0;
2771 GUI_EVENT(d, geCHANGE_VALUE);
2772 change_value = true;
2773 }
2774 else if(scursor < l)
2775 {
2776 for(p=scursor; s[p]; p++)
2777 s[p] = s[p+1];
2778 GUI_EVENT(d, geCHANGE_VALUE);
2779 change_value = true;
2780 }
2781 }
2782 else if(upper_c == KEY_BACKSPACE)
2783 {
2784 if(line_modifier)
2785 {
2786 delete_line(s, &scursor);
2787 ecursor = -1;
2788 GUI_EVENT(d, geCHANGE_VALUE);
2789 change_value = true;
2790 }
2791 else if(word_modifier)
2792 {
2793 delete_word(s, &scursor);
2794 ecursor = -1;
2795 GUI_EVENT(d, geCHANGE_VALUE);
2796 change_value = true;
2797 }
2798 else if(range_selected)
2799 {
2800 ecursor = -1;
2801 scursor = low_cursor;
2802 size_t ind = low_cursor, ind2 = high_cursor+1;
2803 while(ind2 < l && s[ind2])
2804 s[ind++] = s[ind2++];
2805 while(s[ind])
2806 s[ind++] = 0;
2807 GUI_EVENT(d, geCHANGE_VALUE);
2808 change_value = true;
2809 }
2810 else if(scursor > 0)
2811 {
2812 --scursor;
2813 for(p=scursor; s[p]; p++)
2814 s[p] = s[p+1];
2815 GUI_EVENT(d, geCHANGE_VALUE);
2816 change_value = true;
2817 }
2818 }
2819 else if(upper_c == KEY_ENTER)
2820 {
2821 change_cursor = false;
2822 GUI_EVENT(d, geENTER);
2823 if(d->flags & D_EXIT)
2824 {
2825 object_message(d, MSG_DRAW, 0);
2826 return D_CLOSE;
2827 }
2828 else
2829 return D_O_K;
2830 }
2831 else if(upper_c == KEY_TAB)
2832 {
2833 change_cursor = false;
2834 return D_O_K;
2835 }
2836 else if (ctrl && upper_c == KEY_C)
2837 {
2838 change_cursor = false;
2839 std::ostringstream oss;
2840 if(range_selected)
2841 {
2842 for(size_t ind = low_cursor; ind <= high_cursor; ++ind)
2843 {
2844 if(s[ind])
2845 oss << s[ind];
2846 }
2847 }
2848 else
2849 {
2850 if(s[scursor])
2851 oss << s[scursor];
2852 }
2853 set_al_clipboard(oss.str());
2854 }
2855 else if (ctrl && upper_c == KEY_V && clipboard_has_text())
2856 {
2857 std::string cb;
2858 if(get_al_clipboard(cb))
2859 {
2860 int ind = low_cursor, ind2 = high_cursor + 1;
2861 if (range_selected)
2862 {
2863 //Delete selected text
2864 ecursor = -1;
2865 scursor = low_cursor;
2866 while (s[ind2] && ind2 < l)
2867 s[ind++] = s[ind2++];
2868 while (s[ind])
2869 s[ind++] = 0;
2870 l = (int32_t)strlen(s);
2871 }
2872 //Move the text out of the way of the pasting
2873 int paste_len = cb.size();
2874 int paste_start = scursor;
2875 int paste_end = paste_start+paste_len;
2876 ind = strlen(s);
2877 ind2 = ind+paste_len;
2878 while(ind2 > d->d1)
2879 {
2880 --ind;
2881 --ind2;
2882 }
2883 size_t new_l = ind2;
2884 while(ind >= paste_start)
2885 {
2886 if(s[ind] || (ind&&s[ind-1]))
2887 {
2888 s[ind2] = s[ind];
2889 }
2890 --ind2; --ind;
2891 }
2892 for(auto q = 0; q < paste_len && paste_start+q < new_l; ++q)
2893 {
2894 s[paste_start+q] = cb.at(q);
2895 }
2896 s[new_l] = 0;
2897 scursor = paste_start + paste_len;
2898 ecursor = -1;
2899 GUI_EVENT(d, geCHANGE_VALUE);
2900 change_value = true;
2901 }
2902 }
2903 else if (ctrl && upper_c == KEY_A)
2904 {
2905 cursor_start = 0;
2906 cursor_end = (int16_t)strlen((char*)d->dp) - 1;
2907 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2908 d->flags |= D_DIRTY;
2909 break;
2910 }
2911 else if(lower_c >= 32 && !ctrl)
2912 {
2913 if(range_selected)
2914 {
2915 //Delete selected text
2916 ecursor = -1;
2917 scursor = low_cursor;
2918 int ind = low_cursor, ind2 = high_cursor+1;
2919 // ind2 = std::min(ind2, d->d1);
2920 while(s[ind2] && ind2 < l)
2921 s[ind++] = s[ind2++];
2922 while(s[ind])
2923 s[ind++] = 0;
2924 l = (int32_t)strlen(s);
2925 //Type the character in its' place
2926 //(fallthrough)
2927 }
2928 if(l < d->d1)
2929 {
2930 ecursor = -1;
2931 s[l+1] = 0;
2932 size_t ind = l;
2933 while(ind >= scursor)
2934 {
2935 s[ind+1] = s[ind];
2936 if (!ind) break;
2937 --ind;
2938 }
2939
2940 s[scursor++] = lower_c;
2941
2942 GUI_EVENT(d, geCHANGE_VALUE);
2943 change_value = true;
2944 }
2945 }
2946 else
2947 return D_O_K;
2948 if(change_cursor)
2949 {
2950 cursor_end = ecursor; cursor_start = scursor;
2951 if (cursor_end == cursor_start) cursor_end = -1;
2952 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2953 }
2954 /* if we changed something, better redraw... */
2955 // Note: this still redraws when not necessary.
2956 if (change_value || change_cursor)
2957 d->flags |= D_DIRTY;
2958 return D_USED_CHAR;
2959 }
2960 }
2961 return D_O_K;
2962 }
2963
2964 int32_t jwin_hexedit_proc_old(int32_t msg,DIALOG *d,int32_t c)
2965 {
2966 if(msg==MSG_CHAR)
2967 if(((isalpha(c&255) && !isxdigit(c&255))) || ispunct(c&255))
2968 return D_USED_CHAR;
2969
2970 return jwin_edit_proc(msg,d,isalpha(c&255)?c&0xDF:c);
2971 }
2972
2973 bool editproc_special_key(int32_t c)
2974 {
2975 switch(c>>8)
2976 {
2977 case KEY_LEFT: case KEY_RIGHT:
2978 case KEY_HOME: case KEY_END:
2979 case KEY_DEL: case KEY_BACKSPACE:
2980 case KEY_ENTER: case KEY_TAB:
2981 return true;
2982 }
2983 if(key_shifts & KB_CTRL_CMD_FLAG)
2984 switch(c&255)
2985 {
2986 case 'c': case 'C':
2987 return true;
2988 case 'v': case 'V':
2989 return clipboard_has_text();
2990 }
2991 return false;
2992 }
2993 bool editproc_combined_key(int32_t c)
2994 {
2995 if(key_shifts & KB_CTRL_CMD_FLAG)
2996 switch(c&255)
2997 {
2998 case 'c': case 'C':
2999 return true;
3000 case 'v': case 'V':
3001 return clipboard_has_text();
3002 }
3003 return false;
3004 }
3005 int32_t jwin_hexedit_proc(int32_t msg,DIALOG *d,int32_t c)
3006 {
3007 bool caps_paste = false;
3008 if(msg==MSG_CHAR)
3009 {
3010 if(key_shifts & KB_CTRL_CMD_FLAG)
3011 {
3012 if(clipboard_has_text() && ((c&255)=='v' || (c&255)=='V'))
3013 {
3014 std::string cb;
3015 if(get_al_clipboard(cb))
3016 {
3017 if(cb.find_first_not_of("-.0123456789ABCDEFabcdef") != std::string::npos)
3018 return D_USED_CHAR;
3019 if(cb.find_first_of("abcdef") != std::string::npos)
3020 caps_paste = true;
3021 }
3022 else return D_USED_CHAR;
3023 }
3024 }
3025 switch(c&255)
3026 {
3027 case '-': case '.':
3028 case '0': case '1': case '2': case '3': case '4':
3029 case '5': case '6': case '7': case '8': case '9':
3030 case 'A': case 'B': case 'C':
3031 case 'D': case 'E': case 'F':
3032 break;
3033 case 'a': case 'b': case 'c':
3034 case 'd': case 'e': case 'f':
3035 c = (c&~255)|toupper(c&255);
3036 break;
3037 default:
3038 if(!editproc_special_key(c))
3039 return D_O_K;
3040 else if(!editproc_combined_key(c))
3041 c&=~255;
3042 }
3043 }
3044
3045 auto ret = jwin_edit_proc(msg,d,c);
3046 if(caps_paste)
3047 {
3048 char* s = (char*)d->dp;
3049 caps_paste = false;
3050 for(int q = strlen(s)-1; q >= 0; --q)
3051 {
3052 switch(s[q])
3053 {
3054 case 'a': case 'b': case 'c':
3055 case 'd': case 'e': case 'f':
3056 s[q] = toupper(s[q]);
3057 caps_paste = true;
3058 break;
3059 }
3060 }
3061 if(caps_paste)
3062 {
3063 jwin_edit_proc(MSG_DRAW,d,0);
3064 }
3065 }
3066 return ret;
3067 }
3068 int32_t jwin_numedit_proc(int32_t msg,DIALOG *d,int32_t c)
3069 {
3070 if(msg==MSG_CHAR)
3071 {
3072 if(key_shifts & KB_CTRL_CMD_FLAG)
3073 {
3074 if(clipboard_has_text() && ((c&255)=='v' || (c&255)=='V'))
3075 {
3076 std::string cb;
3077 if(get_al_clipboard(cb))
3078 {
3079 if(cb.find_first_not_of("-.0123456789") != std::string::npos)
3080 return D_USED_CHAR;
3081 }
3082 else return D_USED_CHAR;
3083 }
3084 }
3085 switch(c&255)
3086 {
3087 case '-': case '.':
3088 case '0': case '1': case '2': case '3': case '4':
3089 case '5': case '6': case '7': case '8': case '9':
3090 break;
3091 default:
3092 if(!editproc_special_key(c))
3093 return D_O_K;
3094 else if(!editproc_combined_key(c))
3095 c&=~255;
3096 }
3097 }
3098
3099 return jwin_edit_proc(msg,d,c);
3100 }
3101
3102 int32_t jwin_numedit_byte_proc(int32_t msg,DIALOG *d,int32_t c)
3103 {
3104 if ( (atoi((char*)d->dp)) > 255 )
3105 {
3106 strcpy((char*)d->dp,"255\0");
3107 return jwin_numedit_proc(msg,d,c);
3108 }
3109 else if ( (atoi((char*)d->dp)) < 0 )
3110 {
3111 strcpy((char*)d->dp,"0\0");
3112 return jwin_numedit_proc(msg,d,c);
3113 }
3114
3115 return jwin_numedit_proc(msg,d,c);
3116 }
3117
3118 int32_t jwin_numedit_short_proc(int32_t msg,DIALOG *d,int32_t c)
3119 {
3120 if ( (atoi((char*)d->dp)) > 65535 )
3121 {
3122 strcpy((char*)d->dp,"65535\0");
3123 return jwin_numedit_proc(msg,d,c);
3124 }
3125 else if ( (atoi((char*)d->dp)) < 0 )
3126 {
3127 strcpy((char*)d->dp,"0\0");
3128 return jwin_numedit_proc(msg,d,c);
3129 }
3130
3131 return jwin_numedit_proc(msg,d,c);
3132 }
3133
3134 int32_t jwin_numedit_zscriptint_proc(int32_t msg,DIALOG *d,int32_t c)
3135 {
3136 if ( (atoi((char*)d->dp)) > 214748 )
3137 {
3138 strcpy((char*)d->dp,"214748\0");
3139 return jwin_numedit_proc(msg,d,c);
3140 }
3141 else if ( (atoi((char*)d->dp)) < -214748 )
3142 {
3143 strcpy((char*)d->dp,"-214748\0");
3144 return jwin_numedit_proc(msg,d,c);
3145 }
3146
3147 return jwin_numedit_proc(msg,d,c);
3148 }
3149
3150 int32_t jwin_numedit_sshort_proc(int32_t msg,DIALOG *d,int32_t c)
3151 {
3152 if ( (atoi((char*)d->dp)) > 32767 )
3153 {
3154 strcpy((char*)d->dp,"32767\0");
3155 return jwin_numedit_proc(msg,d,c);
3156 }
3157 else if ( (atoi((char*)d->dp)) < -32768 )
3158 {
3159 strcpy((char*)d->dp,"-32768\0");
3160 return jwin_numedit_proc(msg,d,c);
3161 }
3162
3163 return jwin_numedit_proc(msg,d,c);
3164 }
3165
3166 int32_t jwin_numedit_sbyte_proc(int32_t msg,DIALOG *d,int32_t c)
3167 {
3168 if ( (atoi((char*)d->dp)) > 127 )
3169 {
3170 strcpy((char*)d->dp,"127\0");
3171 return jwin_numedit_proc(msg,d,c);
3172 }
3173 else if ( (atoi((char*)d->dp)) < -128 )
3174 {
3175 strcpy((char*)d->dp,"-128\0");
3176 return jwin_numedit_proc(msg,d,c);
3177 }
3178
3179 return jwin_numedit_proc(msg,d,c);
3180 }
3181
3182 // Special numedit procs
3183
3184 void trim_trailing_0s(char* str, bool leaveDec = false)
3185 {
3186 bool foundDec = false;
3187 for(int32_t q = 0; str[q]; ++q)
3188 {
3189 if(str[q] == '.')
3190 {
3191 foundDec = true;
3192 break;
3193 }
3194 }
3195 if(!foundDec) return; //No decimal place, thus no trailing 0's.
3196 for(int32_t q = strlen(str)-1; q > 0; --q)
3197 {
3198 if(str[q] == '0' && (!leaveDec || str[q-1] != '.'))
3199 {
3200 str[q] = 0;
3201 }
3202 else if(str[q] == '.')
3203 {
3204 str[q] = 0;
3205 return;
3206 }
3207 else return;
3208 }
3209 }
3210 int32_t jwin_swapbtn_proc(int32_t msg, DIALOG* d, int32_t c)
3211 {
3212 static const char* swp[nswapMAX] = {"D", "H", "LD", "LH", "B"};
3213 d->dp = (void*)swp[d->d1&0xF];
3214 //d1 is (0xF0 = old val, 0x0F = new val)
3215 //d2 is max val
3216 if(d->d2 < 2 || d->d2 > nswapMAX) return D_O_K; //Not setup yet, or bad value
3217 DIALOG* relproc = (DIALOG*)d->dp3;
3218 GUI::TextField *tf_obj = nullptr;
3219 if(d->d2 > nswapBOOL) tf_obj = (GUI::TextField*)relproc->dp3;
3220 int32_t ret = jwin_button_proc(msg, d, c);
3221 if(d->flags & D_SELECTED) //On selection
3222 {
3223 d->d1 = ((d->d1&0x0F)<<4) | (((d->d1&0x0F)+1)%d->d2);
3224 d->dp = (void*)swp[d->d1&0xF];
3225 d->flags &= ~D_SELECTED;
3226 if(tf_obj) tf_obj->refresh_cb_swap();
3227 if(relproc)
3228 {
3229 object_message(relproc, MSG_DRAW, 0);
3230 }
3231 object_message(d, MSG_DRAW, 0);
3232 }
3233 return ret;
3234 }
3235 int32_t jwin_numedit_swap_byte_proc(int32_t msg, DIALOG *d, int32_t c)
3236 {
3237 DIALOG* swapbtn;
3238 if(d->flags&D_NEW_GUI)
3239 {
3240 swapbtn = d+1;
3241 }
3242 else swapbtn = (DIALOG*)d->dp3;
3243 if(!swapbtn) return D_O_K;
3244 if(msg==MSG_START) //Setup the swapbtn
3245 {
3246 d->bg = 0;
3247 swapbtn->d2 = 2; //Max states
3248 auto ty = swapbtn->d1&0xF;
3249 if(unsigned(ty) > swapbtn->d2)
3250 swapbtn->d1 &= ~0xF;
3251 swapbtn->dp3 = (void*)d;
3252 }
3253 int32_t ret = D_O_K;
3254 int32_t ntype = swapbtn->d1&0xF,
3255 otype = swapbtn->d1>>4;
3256
3257 char* str = (char*)d->dp;
3258 int32_t v = 0;
3259 if(msg == MSG_START)
3260 v = d->fg;
3261 else switch(otype)
3262 {
3263 case nswapDEC:
3264 v = atoi(str);
3265 break;
3266 case nswapHEX:
3267 v = zc_xtoi(str);
3268 break;
3269 }
3270 byte b;
3271 if ( v > 255 )
3272 b=255;
3273 else if ( v < 0 )
3274 b=0;
3275 else b = (byte)v;
3276 if(msg==MSG_CHAR && ((c&255)=='-'))
3277 {
3278 //unsigned//b = -b;
3279 c &= ~255;
3280 }
3281 if(unsigned(v) != b || otype != ntype || msg == MSG_START)
3282 {
3283 switch(ntype)
3284 {
3285 case nswapDEC:
3286 sprintf(str, "%d", b);
3287 break;
3288 case nswapHEX:
3289 sprintf(str, "%X", b);
3290 break;
3291 }
3292 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3293 }
3294
3295 if(d->fg != b)
3296 {
3297 d->fg = b; //Store numeric data
3298 GUI_EVENT(d, geUPDATE_SWAP);
3299 }
3300 switch(ntype)
3301 {
3302 case nswapDEC:
3303 d->d1 = 3; //3 digits max
3304 ret |= jwin_numedit_proc(msg, d, c);
3305 break;
3306 case nswapHEX:
3307 d->d1 = 2; //2 digits max
3308 if(msg == MSG_CHAR && isalpha(c&255)) //always capitalize
3309 c = (c&~255) | (toupper(c&255));
3310 ret |= jwin_hexedit_proc(msg, d, c);
3311 break;
3312 }
3313
3314 swapbtn->d1 = (ntype<<4)|ntype; //Mark the type change processed
3315
3316 return ret;
3317 }
3318 #define INC_TF_CURSORS(val,inc,max) \
3319 do \
3320 { \
3321 int32_t scursor = (val & 0xFFFF)+inc; \
3322 int32_t ecursor = (val & 0xFFFF0000) >> 16; \
3323 bool valid_ecursor = ecursor != 0xFFFF; \
3324 if(valid_ecursor) ecursor += inc; \
3325 if(inc < 0) \
3326 { \
3327 if(scursor < 0) scursor = 0; \
3328 if(valid_ecursor && ecursor < 0) ecursor = 0; \
3329 } \
3330 else \
3331 { \
3332 if(scursor > max) scursor = max; \
3333 if(valid_ecursor && ecursor > max) ecursor = max; \
3334 } \
3335 val = scursor | (ecursor<<16); \
3336 } while(false)
3337 int32_t jwin_numedit_swap_sshort_proc(int32_t msg, DIALOG *d, int32_t c)
3338 {
3339 const size_t maxlen = 7;
3340 DIALOG* swapbtn;
3341 if(d->flags&D_NEW_GUI)
3342 {
3343 swapbtn = d+1;
3344 }
3345 else swapbtn = (DIALOG*)d->dp3;
3346 if(!swapbtn) return D_O_K;
3347 if(msg==MSG_START) //Setup the swapbtn
3348 {
3349 d->bg = 0;
3350 swapbtn->d2 = 2; //Max states
3351 auto ty = swapbtn->d1&0xF;
3352 if(unsigned(ty) > swapbtn->d2)
3353 swapbtn->d1 &= ~0xF;
3354 swapbtn->dp3 = (void*)d;
3355 }
3356 int32_t ret = D_O_K;
3357 int32_t ntype = swapbtn->d1&0xF,
3358 otype = swapbtn->d1>>4;
3359
3360 char* str = (char*)d->dp;
3361 int32_t v = 0;
3362 if(msg == MSG_START)
3363 v = d->fg;
3364 else switch(otype)
3365 {
3366 case nswapDEC:
3367 v = atoi(str);
3368 break;
3369 case nswapHEX:
3370 v = zc_xtoi(str);
3371 break;
3372 }
3373 int16_t b;
3374 if ( v > 32767 )
3375 b=32767;
3376 else if ( v < -32768 )
3377 b=-32768;
3378 else b = (int16_t)v;
3379 bool queued_neg = d->bg;
3380 if(msg==MSG_CHAR && ((c&255)=='-'))
3381 {
3382 if(b)
3383 {
3384 b = -b;
3385 v = b;
3386 if(b<0)
3387 {
3388 if(str[0] != '-')
3389 {
3390 char buf[16] = {0};
3391 strcpy(buf, str);
3392 sprintf(str, "-%s", buf);
3393 INC_TF_CURSORS(d->d2,1,strlen(str));
3394 }
3395 }
3396 else if(str[0] == '-')
3397 {
3398 char buf[16] = {0};
3399 strcpy(buf, str);
3400 sprintf(str, "%s", buf+1);
3401 INC_TF_CURSORS(d->d2,-1,strlen(str));
3402 }
3403 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3404 }
3405 else queued_neg = !queued_neg; //queue the negative
3406 c &= ~255;
3407 ret |= D_USED_CHAR;
3408 }
3409 if(b && queued_neg)
3410 {
3411 //b = -b; //actually, 'atoi' handles it for us.....
3412 queued_neg = false;
3413 }
3414 if(bool(d->bg) != queued_neg)
3415 {
3416 d->bg = queued_neg;
3417 if(queued_neg)
3418 {
3419 if(str[0] != '-')
3420 {
3421 char buf[16] = {0};
3422 strcpy(buf, str);
3423 sprintf(str, "-%s", buf);
3424 INC_TF_CURSORS(d->d2,1,strlen(str));
3425 }
3426 }
3427 else if(!b && str[0] == '-')
3428 {
3429 char buf[16] = {0};
3430 strcpy(buf, str);
3431 sprintf(str, "%s", buf+1);
3432 INC_TF_CURSORS(d->d2,-1,strlen(str));
3433 }
3434 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3435 }
3436 if(v != b || otype != ntype || msg == MSG_START)
3437 {
3438 switch(ntype)
3439 {
3440 case nswapDEC:
3441 sprintf(str, "%d", b);
3442 break;
3443 case nswapHEX:
3444 if(b<0)
3445 sprintf(str, "-%X", -b);
3446 else sprintf(str, "%X", b);
3447 break;
3448 }
3449 d->d2 = 0xFFFF0000|strlen(str);
3450 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3451 }
3452
3453 if(d->fg != b)
3454 {
3455 d->fg = b; //Store numeric data
3456 GUI_EVENT(d, geUPDATE_SWAP);
3457 }
3458 bool rev_d2 = false;
3459 int32_t old_d2 = d->d2;
3460 int32_t ref_d2;
3461 if(msg == MSG_CHAR && queued_neg)
3462 {
3463 auto scursor = d->d2 & 0xFFFF;
3464 auto ecursor = (d->d2 & 0xFFFF0000) >> 16;
3465 if(!scursor)
3466 {
3467 rev_d2 = true;
3468 INC_TF_CURSORS(d->d2,1,strlen(str));
3469 ref_d2 = d->d2;
3470 }
3471 }
3472 switch(ntype)
3473 {
3474 case nswapDEC:
3475 d->d1 = 6; //6 digits max (incl '-')
3476 ret |= jwin_numedit_proc(msg, d, c);
3477 break;
3478 case nswapHEX:
3479 d->d1 = 5; //5 digits max (incl '-')
3480 if(msg == MSG_CHAR && !editproc_special_key(c) && isalpha(c&255)) //always capitalize
3481 c = (c&~255) | (toupper(c&255));
3482 ret |= jwin_hexedit_proc(msg, d, c);
3483 break;
3484 }
3485 if(rev_d2 && ref_d2 == d->d2)
3486 {
3487 d->d2 = old_d2;
3488 }
3489
3490 swapbtn->d1 = (ntype<<4)|ntype; //Mark the type change processed
3491
3492 return ret;
3493 }
3494 int32_t jwin_numedit_swap_zsint_proc(int32_t msg, DIALOG *d, int32_t c)
3495 {
3496 const size_t maxlen = 13;
3497 DIALOG* swapbtn;
3498 if(d->flags&D_NEW_GUI)
3499 {
3500 swapbtn = d+1;
3501 }
3502 else swapbtn = (DIALOG*)d->dp3;
3503 if(!swapbtn) return D_O_K;
3504 if(msg==MSG_START) //Setup the swapbtn
3505 {
3506 d->bg = 0;
3507 swapbtn->d2 = 4; //Max states
3508 auto ty = swapbtn->d1&0xF;
3509 if(unsigned(ty) > swapbtn->d2)
3510 swapbtn->d1 &= ~0xF;
3511 swapbtn->dp3 = (void*)d;
3512 }
3513 int32_t ret = D_O_K;
3514 int32_t ntype = swapbtn->d1&0xF,
3515 otype = swapbtn->d1>>4;
3516
3517 char* str = (char*)d->dp;
3518 int64_t v = 0;
3519 if(msg == MSG_START)
3520 v = d->fg;
3521 else switch(otype)
3522 {
3523 case nswapDEC:
3524 if(char *ptr = strchr(str, '.'))
3525 {
3526 char tempstr[32] = {0};
3527 strcpy(tempstr, str);
3528 for(int32_t q = 0; q < 4; ++q)
3529 tempstr[strlen(str)+q]='0';
3530 ptr = strchr(tempstr, '.');
3531 *ptr=0;++ptr;*(ptr+4)=0; //Nullchar at 2 positions to limit strings
3532 v = atoi(tempstr);
3533 v *= 10000;
3534 if(tempstr[0] == '-')
3535 v -= atoi(ptr);
3536 else v += atoi(ptr);
3537 }
3538 else
3539 {
3540 v = atoi(str);
3541 v *= 10000;
3542 }
3543 break;
3544 case nswapHEX:
3545 if(char *ptr = strchr(str, '.'))
3546 {
3547 char tempstr[32] = {0};
3548 strcpy(tempstr, str);
3549 for(int32_t q = 0; q < 4; ++q)
3550 tempstr[strlen(str)+q]='0';
3551 ptr = strchr(tempstr, '.');
3552 *ptr=0;++ptr;*(ptr+4)=0; //Nullchar at 2 positions to limit strings
3553 v = zc_xtoi(tempstr);
3554 v *= 10000;
3555 if(tempstr[0] == '-')
3556 v -= atoi(ptr);
3557 else v += atoi(ptr);
3558 }
3559 else
3560 {
3561 v = zc_xtoi(str);
3562 v *= 10000;
3563 }
3564 break;
3565 case nswapLDEC:
3566 v = zc_atoi64(str);
3567 break;
3568 case nswapLHEX:
3569 v = zc_xtoi64(str);
3570 break;
3571 }
3572 int32_t b;
3573 if ( v > 2147483647 )
3574 b=2147483647;
3575 else if ( v < INT_MIN )
3576 b=INT_MIN;
3577 else b = (int32_t)v;
3578 bool queued_neg = d->bg;
3579 if(msg==MSG_CHAR && ((c&255)=='-'))
3580 {
3581 if(b)
3582 {
3583 if(b==INT_MIN)
3584 ++b;
3585 b = -b;
3586 v = b;
3587 if(b<0)
3588 {
3589 if(str[0] != '-')
3590 {
3591 char buf[16] = {0};
3592 strcpy(buf, str);
3593 sprintf(str, "-%s", buf);
3594 INC_TF_CURSORS(d->d2,1,strlen(str));
3595 }
3596 }
3597 else if(str[0] == '-')
3598 {
3599 char buf[16] = {0};
3600 strcpy(buf, str);
3601 sprintf(str, "%s", buf+1);
3602 INC_TF_CURSORS(d->d2,-1,strlen(str));
3603 }
3604 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3605 }
3606 else queued_neg = !queued_neg; //queue negative
3607 c &= ~255;
3608 ret |= D_USED_CHAR;
3609 }
3610 if(b && queued_neg)
3611 {
3612 //b = -b; //actually, 'atoi' handles it for us.....
3613 queued_neg = false;
3614 }
3615 if(bool(d->bg) != queued_neg)
3616 {
3617 d->bg = queued_neg;
3618 if(queued_neg)
3619 {
3620 if(str[0] != '-')
3621 {
3622 char buf[16] = {0};
3623 strcpy(buf, str);
3624 sprintf(str, "-%s", buf);
3625 INC_TF_CURSORS(d->d2,1,strlen(str));
3626 }
3627 }
3628 else if(!b && str[0] == '-')
3629 {
3630 char buf[16] = {0};
3631 strcpy(buf, str);
3632 sprintf(str, "%s", buf+1);
3633 INC_TF_CURSORS(d->d2,-1,strlen(str));
3634 }
3635 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3636 }
3637 if(v != b || otype != ntype || msg == MSG_START)
3638 {
3639 switch(ntype)
3640 {
3641 case nswapDEC:
3642 if(b < 0)
3643 sprintf(str, "-%ld.%04ld", abs(b/10000L), abs(b%10000L));
3644 else sprintf(str, "%ld.%04ld", b/10000L, b%10000L);
3645 trim_trailing_0s(str);
3646 break;
3647 case nswapHEX:
3648 if(b<0)
3649 sprintf(str, "-%lX.%04ld", abs(b/10000L), abs(b%10000L));
3650 else sprintf(str, "%lX.%04ld", b/10000L, abs(b%10000L));
3651 trim_trailing_0s(str);
3652 break;
3653 case nswapLDEC:
3654 sprintf(str, "%d", b);
3655 break;
3656 case nswapLHEX:
3657 if(b<0)
3658 sprintf(str, "-%X", -b);
3659 else sprintf(str, "%X", b);
3660 break;
3661 }
3662 d->d2 = 0xFFFF0000|strlen(str);
3663 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3664 }
3665 if(d->fg != b)
3666 {
3667 d->fg = b; //Store numeric data
3668 GUI_EVENT(d, geUPDATE_SWAP);
3669 }
3670 if(msg==MSG_CHAR && ((c&255)=='.'))
3671 {
3672 if(ntype >= nswapLDEC) //No '.' in long modes
3673 c&=~255;
3674 else
3675 {
3676 for(int32_t q = 0; str[q]; ++q)
3677 {
3678 if(str[q] == '.') //Only one '.'
3679 {
3680 c&=~255;
3681 break;
3682 }
3683 }
3684 }
3685 }
3686 bool rev_d2 = false;
3687 int32_t old_d2 = d->d2;
3688 int32_t ref_d2;
3689 if(msg == MSG_CHAR && queued_neg)
3690 {
3691 auto scursor = d->d2 & 0xFFFF;
3692 auto ecursor = (d->d2 & 0xFFFF0000) >> 16;
3693 if(!scursor)
3694 {
3695 rev_d2 = true;
3696 INC_TF_CURSORS(d->d2,1,strlen(str));
3697 ref_d2 = d->d2;
3698 }
3699 }
3700 bool areaselect = (d->d2 & 0xFFFF0000) != 0xFFFF0000;
3701 switch(ntype)
3702 {
3703 case nswapDEC:
3704 d->d1 = 12; //12 digits max (incl '-', '.')
3705 if(msg==MSG_CHAR && !editproc_special_key(c) && !areaselect)
3706 {
3707 int32_t p = 0;
3708 for(int32_t q = 0; str[q]; ++q)
3709 {
3710 if(str[q]=='.')
3711 {
3712 if((d->d2&0x0000FFFF) <= q)
3713 break; //typing before the '.'
3714 ++p;
3715 }
3716 else if(p) ++p;
3717 }
3718 if(p>=5) //too many chars after '.'
3719 c&=~255;
3720 }
3721 ret |= jwin_numedit_proc(msg, d, c);
3722 break;
3723 case nswapHEX:
3724 d->d1 = 11; //11 digits max (incl '-', '.')
3725 if(msg==MSG_CHAR && !editproc_special_key(c))
3726 {
3727 if(!((c&255)=='.'||isxdigit(c&255)))
3728 c&=~255;
3729 else if(isxdigit(c&255) && !isdigit(c&255))
3730 for(int32_t q = 0; q < (d->d2&0x0000FFFF) && str[q]; ++q)
3731 {
3732 if(str[q] == '.') //No hex digits to the right of the '.'
3733 {
3734 c&=~255;
3735 break;
3736 }
3737 }
3738 if((c&255) && !areaselect)
3739 {
3740 int32_t p = 0;
3741 for(int32_t q = 0; str[q]; ++q)
3742 {
3743 if(str[q]=='.')
3744 {
3745 if((d->d2&0x0000FFFF) <= q)
3746 break; //typing before the '.'
3747 ++p;
3748 }
3749 else if(p) ++p;
3750 }
3751 if(p>=5) //too many chars after '.'
3752 c&=~255;
3753 }
3754 if(isalpha(c&255)) //always capitalize
3755 c = (c&~255) | (toupper(c&255));
3756 }
3757 ret |= jwin_hexedit_proc(msg, d, c);
3758 break;
3759 case nswapLDEC:
3760 d->d1 = 11; //11 digits max (incl '-')
3761 ret |= jwin_numedit_proc(msg, d, c);
3762 break;
3763 case nswapLHEX:
3764 d->d1 = 9; //9 digits max (incl '-')
3765 if(msg == MSG_CHAR && !editproc_special_key(c) && isalpha(c&255)) //always capitalize
3766 c = (c&~255) | (toupper(c&255));
3767 ret |= jwin_hexedit_proc(msg, d, c);
3768 break;
3769 }
3770 if(rev_d2 && ref_d2 == d->d2)
3771 {
3772 d->d2 = old_d2;
3773 }
3774
3775 swapbtn->d1 = (ntype<<4)|ntype; //Mark the type change processed
3776
3777 return ret;
3778 }
3779 int32_t jwin_numedit_swap_zsint_nodec_proc(int32_t msg, DIALOG *d, int32_t c)
3780 {
3781 const size_t maxlen = 7;
3782 DIALOG* swapbtn;
3783 if(d->flags&D_NEW_GUI)
3784 {
3785 swapbtn = d+1;
3786 }
3787 else swapbtn = (DIALOG*)d->dp3;
3788 if(!swapbtn) return D_O_K;
3789 if(msg==MSG_START) //Setup the swapbtn
3790 {
3791 d->bg = 0;
3792 swapbtn->d2 = 2; //Max states
3793 auto ty = swapbtn->d1&0xF;
3794 if(unsigned(ty) > swapbtn->d2)
3795 swapbtn->d1 &= ~0xF;
3796 swapbtn->dp3 = (void*)d;
3797 }
3798 int32_t ret = D_O_K;
3799 int32_t ntype = swapbtn->d1&0xF,
3800 otype = swapbtn->d1>>4;
3801
3802 char* str = (char*)d->dp;
3803 int64_t v = 0;
3804 if(msg == MSG_START)
3805 v = d->fg;
3806 else switch(otype)
3807 {
3808 case nswapDEC:
3809 v = atoi(str);
3810 v *= 10000;
3811 break;
3812 case nswapHEX:
3813 v = zc_xtoi(str);
3814 v *= 10000;
3815 break;
3816 }
3817 int32_t b;
3818 if ( v > 2147480000 )
3819 b=2147480000;
3820 else if ( v < -2147480000 )
3821 b=-2147480000;
3822 else b = (int32_t)v;
3823 bool queued_neg = d->bg;
3824 if(msg==MSG_CHAR && ((c&255)=='-'))
3825 {
3826 if(b)
3827 {
3828 if(b==INT_MIN)
3829 ++b;
3830 b = -b;
3831 v = b;
3832 if(b<0)
3833 {
3834 if(str[0] != '-')
3835 {
3836 char buf[16] = {0};
3837 strcpy(buf, str);
3838 sprintf(str, "-%s", buf);
3839 INC_TF_CURSORS(d->d2,1,strlen(str));
3840 }
3841 }
3842 else if(str[0] == '-')
3843 {
3844 char buf[16] = {0};
3845 strcpy(buf, str);
3846 sprintf(str, "%s", buf+1);
3847 INC_TF_CURSORS(d->d2,-1,strlen(str));
3848 }
3849 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3850 }
3851 else queued_neg = !queued_neg; //queue negative
3852 c &= ~255;
3853 ret |= D_USED_CHAR;
3854 }
3855 if(b && queued_neg)
3856 {
3857 //b = -b; //actually, 'atoi' handles it for us.....
3858 queued_neg = false;
3859 }
3860 if(bool(d->bg) != queued_neg)
3861 {
3862 d->bg = queued_neg;
3863 if(queued_neg)
3864 {
3865 if(str[0] != '-')
3866 {
3867 char buf[16] = {0};
3868 strcpy(buf, str);
3869 sprintf(str, "-%s", buf);
3870 INC_TF_CURSORS(d->d2,1,strlen(str));
3871 }
3872 }
3873 else if(!b && str[0] == '-')
3874 {
3875 char buf[16] = {0};
3876 strcpy(buf, str);
3877 sprintf(str, "%s", buf+1);
3878 INC_TF_CURSORS(d->d2,-1,strlen(str));
3879 }
3880 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3881 }
3882 if(v != b || otype != ntype || msg == MSG_START)
3883 {
3884 switch(ntype)
3885 {
3886 case nswapDEC:
3887 if(b < 0)
3888 sprintf(str, "-%ld", abs(b/10000L));
3889 else sprintf(str, "%ld", b/10000L);
3890 break;
3891 case nswapHEX:
3892 if(b<0)
3893 sprintf(str, "-%lX", abs(b/10000L));
3894 else sprintf(str, "%lX", b/10000L);
3895 break;
3896 }
3897 d->d2 = 0xFFFF0000|strlen(str);
3898 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3899 }
3900 if(d->fg != b)
3901 {
3902 d->fg = b; //Store numeric data
3903 GUI_EVENT(d, geUPDATE_SWAP);
3904 }
3905 if(msg==MSG_CHAR && ((c&255)=='.'))
3906 {
3907 c&=~255; //no '.' in nodec version
3908 }
3909 bool rev_d2 = false;
3910 int32_t old_d2 = d->d2;
3911 int32_t ref_d2;
3912 if(msg == MSG_CHAR && queued_neg)
3913 {
3914 auto scursor = d->d2 & 0xFFFF;
3915 auto ecursor = (d->d2 & 0xFFFF0000) >> 16;
3916 if(!scursor)
3917 {
3918 rev_d2 = true;
3919 INC_TF_CURSORS(d->d2,1,strlen(str));
3920 ref_d2 = d->d2;
3921 }
3922 }
3923 bool areaselect = (d->d2 & 0xFFFF0000) != 0xFFFF0000;
3924 switch(ntype)
3925 {
3926 case nswapDEC:
3927 d->d1 = 7; //7 digits max (incl '-')
3928 ret |= jwin_numedit_proc(msg, d, c);
3929 break;
3930 case nswapHEX:
3931 d->d1 = 6; //6 digits max (incl '-')
3932 if(msg==MSG_CHAR && !editproc_special_key(c))
3933 {
3934 if(!isxdigit(c&255))
3935 c&=~255;
3936 if(isalpha(c&255)) //always capitalize
3937 c = (c&~255) | (toupper(c&255));
3938 }
3939 ret |= jwin_hexedit_proc(msg, d, c);
3940 break;
3941 }
3942 if(rev_d2 && ref_d2 == d->d2)
3943 {
3944 d->d2 = old_d2;
3945 }
3946
3947 swapbtn->d1 = (ntype<<4)|ntype; //Mark the type change processed
3948
3949 return ret;
3950 }
3951 int32_t jwin_numedit_swap_zsint2_proc(int32_t msg, DIALOG *d, int32_t c)
3952 {
3953 const size_t maxlen = 13;
3954 DIALOG* swapbtn;
3955 ASSERT(d->flags&D_NEW_GUI);
3956 swapbtn = d+1;
3957 if(!swapbtn) return D_O_K;
3958 GUI::TextField *tf_obj = (GUI::TextField*)d->dp3;
3959 if(!tf_obj) return D_O_K;
3960 if(msg==MSG_START) //Setup the swapbtn
3961 {
3962 d->bg = 0;
3963 swapbtn->d2 = 5; //Max states
3964 auto ty = swapbtn->d1&0xF;
3965 if(unsigned(ty) > swapbtn->d2)
3966 swapbtn->d1 &= ~0xF;
3967 swapbtn->dp3 = (void*)d;
3968 }
3969 int32_t ret = D_O_K;
3970 int32_t ntype = swapbtn->d1&0xF,
3971 otype = swapbtn->d1>>4;
3972 if(otype==nswapBOOL || ntype == nswapBOOL)
3973 {
3974 if(otype != ntype)
3975 {
3976 tf_obj->refresh_cb_swap();
3977 }
3978 if(ntype == nswapBOOL)
3979 {
3980 swapbtn->d1 = (ntype<<4)|ntype;
3981 return D_O_K;
3982 }
3983 }
3984
3985 char* str = (char*)d->dp;
3986 int64_t v = 0;
3987 if(msg == MSG_START)
3988 v = d->fg;
3989 else switch(otype)
3990 {
3991 case nswapDEC:
3992 if(char *ptr = strchr(str, '.'))
3993 {
3994 char tempstr[32] = {0};
3995 strcpy(tempstr, str);
3996 for(int32_t q = 0; q < 4; ++q)
3997 tempstr[strlen(str)+q]='0';
3998 ptr = strchr(tempstr, '.');
3999 *ptr=0;++ptr;*(ptr+4)=0; //Nullchar at 2 positions to limit strings
4000 v = atoi(tempstr);
4001 v *= 10000;
4002 if(tempstr[0] == '-')
4003 v -= atoi(ptr);
4004 else v += atoi(ptr);
4005 }
4006 else
4007 {
4008 v = atoi(str);
4009 v *= 10000;
4010 }
4011 break;
4012 case nswapHEX:
4013 if(char *ptr = strchr(str, '.'))
4014 {
4015 char tempstr[32] = {0};
4016 strcpy(tempstr, str);
4017 for(int32_t q = 0; q < 4; ++q)
4018 tempstr[strlen(str)+q]='0';
4019 ptr = strchr(tempstr, '.');
4020 *ptr=0;++ptr;*(ptr+4)=0; //Nullchar at 2 positions to limit strings
4021 v = zc_xtoi(tempstr);
4022 v *= 10000;
4023 if(tempstr[0] == '-')
4024 v -= atoi(ptr);
4025 else v += atoi(ptr);
4026 }
4027 else
4028 {
4029 v = zc_xtoi(str);
4030 v *= 10000;
4031 }
4032 break;
4033 case nswapLDEC:
4034 v = zc_atoi64(str);
4035 break;
4036 case nswapLHEX:
4037 v = zc_xtoi64(str);
4038 break;
4039 case nswapBOOL:
4040 v = d->fg;
4041 break;
4042 }
4043 int32_t b;
4044 if ( v > 2147483647 )
4045 b=2147483647;
4046 else if ( v < INT_MIN )
4047 b=INT_MIN;
4048 else b = (int32_t)v;
4049 bool queued_neg = d->bg;
4050 if(msg==MSG_CHAR && ((c&255)=='-'))
4051 {
4052 if(b)
4053 {
4054 if(b==INT_MIN)
4055 ++b;
4056 b = -b;
4057 v = b;
4058 if(b<0)
4059 {
4060 if(str[0] != '-')
4061 {
4062 char buf[16] = {0};
4063 strcpy(buf, str);
4064 sprintf(str, "-%s", buf);
4065 INC_TF_CURSORS(d->d2,1,strlen(str));
4066 }
4067 }
4068 else if(str[0] == '-')
4069 {
4070 char buf[16] = {0};
4071 strcpy(buf, str);
4072 sprintf(str, "%s", buf+1);
4073 INC_TF_CURSORS(d->d2,-1,strlen(str));
4074 }
4075 if(msg != MSG_DRAW) ret |= D_REDRAWME;
4076 }
4077 else queued_neg = !queued_neg; //queue negative
4078 c &= ~255;
4079 ret |= D_USED_CHAR;
4080 }
4081 if(b && queued_neg)
4082 {
4083 //b = -b; //actually, 'atoi' handles it for us.....
4084 queued_neg = false;
4085 }
4086 if(bool(d->bg) != queued_neg)
4087 {
4088 d->bg = queued_neg;
4089 if(queued_neg)
4090 {
4091 if(str[0] != '-')
4092 {
4093 char buf[16] = {0};
4094 strcpy(buf, str);
4095 sprintf(str, "-%s", buf);
4096 INC_TF_CURSORS(d->d2,1,strlen(str));
4097 }
4098 }
4099 else if(!b && str[0] == '-')
4100 {
4101 char buf[16] = {0};
4102 strcpy(buf, str);
4103 sprintf(str, "%s", buf+1);
4104 INC_TF_CURSORS(d->d2,-1,strlen(str));
4105 }
4106 if(msg != MSG_DRAW) ret |= D_REDRAWME;
4107 }
4108 if(v != b || otype != ntype || msg == MSG_START)
4109 {
4110 switch(ntype)
4111 {
4112 case nswapDEC:
4113 if(b < 0)
4114 sprintf(str, "-%ld.%04ld", abs(b/10000L), abs(b%10000L));
4115 else sprintf(str, "%ld.%04ld", b/10000L, b%10000L);
4116 trim_trailing_0s(str);
4117 break;
4118 case nswapHEX:
4119 if(b<0)
4120 sprintf(str, "-%lX.%04ld", abs(b/10000L), abs(b%10000L));
4121 else sprintf(str, "%lX.%04ld", b/10000L, abs(b%10000L));
4122 trim_trailing_0s(str);
4123 break;
4124 case nswapLDEC:
4125 sprintf(str, "%d", b);
4126 break;
4127 case nswapLHEX:
4128 if(b<0)
4129 sprintf(str, "-%X", -b);
4130 else sprintf(str, "%X", b);
4131 break;
4132 }
4133 d->d2 = 0xFFFF0000|strlen(str);
4134 if(msg != MSG_DRAW) ret |= D_REDRAWME;
4135 }
4136 if(d->fg != b)
4137 {
4138 d->fg = b; //Store numeric data
4139 GUI_EVENT(d, geUPDATE_SWAP);
4140 }
4141 if(msg==MSG_CHAR && ((c&255)=='.'))
4142 {
4143 if(ntype >= nswapLDEC) //No '.' in long modes
4144 c&=~255;
4145 else
4146 {
4147 for(int32_t q = 0; str[q]; ++q)
4148 {
4149 if(str[q] == '.') //Only one '.'
4150 {
4151 c&=~255;
4152 break;
4153 }
4154 }
4155 }
4156 }
4157 bool rev_d2 = false;
4158 int32_t old_d2 = d->d2;
4159 int32_t ref_d2;
4160 if(msg == MSG_CHAR && queued_neg)
4161 {
4162 auto scursor = d->d2 & 0xFFFF;
4163 auto ecursor = (d->d2 & 0xFFFF0000) >> 16;
4164 if(!scursor)
4165 {
4166 rev_d2 = true;
4167 INC_TF_CURSORS(d->d2,1,strlen(str));
4168 ref_d2 = d->d2;
4169 }
4170 }
4171 bool areaselect = (d->d2 & 0xFFFF0000) != 0xFFFF0000;
4172 switch(ntype)
4173 {
4174 case nswapDEC:
4175 d->d1 = 12; //12 digits max (incl '-', '.')
4176 if(msg==MSG_CHAR && !editproc_special_key(c) && !areaselect)
4177 {
4178 int32_t p = 0;
4179 for(int32_t q = 0; str[q]; ++q)
4180 {
4181 if(str[q]=='.')
4182 {
4183 if((d->d2&0x0000FFFF) <= q)
4184 break; //typing before the '.'
4185 ++p;
4186 }
4187 else if(p) ++p;
4188 }
4189 if(p>=5) //too many chars after '.'
4190 c&=~255;
4191 }
4192 ret |= jwin_numedit_proc(msg, d, c);
4193 break;
4194 case nswapHEX:
4195 d->d1 = 11; //11 digits max (incl '-', '.')
4196 if(msg==MSG_CHAR && !editproc_special_key(c))
4197 {
4198 if(!((c&255)=='.'||isxdigit(c&255)))
4199 c&=~255;
4200 else if(isxdigit(c&255) && !isdigit(c&255))
4201 for(int32_t q = 0; q < (d->d2&0x0000FFFF) && str[q]; ++q)
4202 {
4203 if(str[q] == '.') //No hex digits to the right of the '.'
4204 {
4205 c&=~255;
4206 break;
4207 }
4208 }
4209 if((c&255) && !areaselect)
4210 {
4211 int32_t p = 0;
4212 for(int32_t q = 0; str[q]; ++q)
4213 {
4214 if(str[q]=='.')
4215 {
4216 if((d->d2&0x0000FFFF) <= q)
4217 break; //typing before the '.'
4218 ++p;
4219 }
4220 else if(p) ++p;
4221 }
4222 if(p>=5) //too many chars after '.'
4223 c&=~255;
4224 }
4225 if(isalpha(c&255)) //always capitalize
4226 c = (c&~255) | (toupper(c&255));
4227 }
4228 ret |= jwin_hexedit_proc(msg, d, c);
4229 break;
4230 case nswapLDEC:
4231 d->d1 = 11; //11 digits max (incl '-')
4232 ret |= jwin_numedit_proc(msg, d, c);
4233 break;
4234 case nswapLHEX:
4235 d->d1 = 9; //9 digits max (incl '-')
4236 if(msg == MSG_CHAR && !editproc_special_key(c) && isalpha(c&255)) //always capitalize
4237 c = (c&~255) | (toupper(c&255));
4238 ret |= jwin_hexedit_proc(msg, d, c);
4239 break;
4240 }
4241 if(rev_d2 && ref_d2 == d->d2)
4242 {
4243 d->d2 = old_d2;
4244 }
4245
4246 swapbtn->d1 = (ntype<<4)|ntype; //Mark the type change processed
4247
4248 if(msg==MSG_START)
4249 tf_obj->refresh_cb_swap();
4250
4251 return ret;
4252 }
4253 int32_t jwin_numedit_noswap_zsint_proc(int32_t msg, DIALOG *d, int32_t c)
4254 {
4255 const size_t maxlen = 13;
4256 ASSERT(d->flags&D_NEW_GUI);
4257 GUI::TextField *tf_obj = (GUI::TextField*)d->dp3;
4258 if(!tf_obj) return D_O_K;
4259 int32_t ret = D_O_K;
4260 int32_t type = tf_obj->getSwapType();
4261
4262 char* str = (char*)d->dp;
4263 int64_t v = 0;
4264 if(msg == MSG_START)
4265 v = d->fg;
4266 else switch(type)
4267 {
4268 case nswapDEC:
4269 if(char *ptr = strchr(str, '.'))
4270 {
4271 char tempstr[32] = {0};
4272 strcpy(tempstr, str);
4273 for(int32_t q = 0; q < 4; ++q)
4274 tempstr[strlen(str)+q]='0';
4275 ptr = strchr(tempstr, '.');
4276 *ptr=0;++ptr;*(ptr+4)=0; //Nullchar at 2 positions to limit strings
4277 v = atoi(tempstr);
4278 v *= 10000;
4279 if(tempstr[0] == '-')
4280 v -= atoi(ptr);
4281 else v += atoi(ptr);
4282 }
4283 else
4284 {
4285 v = atoi(str);
4286 v *= 10000;
4287 }
4288 break;
4289 case nswapHEX:
4290 if(char *ptr = strchr(str, '.'))
4291 {
4292 char tempstr[32] = {0};
4293 strcpy(tempstr, str);
4294 for(int32_t q = 0; q < 4; ++q)
4295 tempstr[strlen(str)+q]='0';
4296 ptr = strchr(tempstr, '.');
4297 *ptr=0;++ptr;*(ptr+4)=0; //Nullchar at 2 positions to limit strings
4298 v = zc_xtoi(tempstr);
4299 v *= 10000;
4300 if(tempstr[0] == '-')
4301 v -= atoi(ptr);
4302 else v += atoi(ptr);
4303 }
4304 else
4305 {
4306 v = zc_xtoi(str);
4307 v *= 10000;
4308 }
4309 break;
4310 case nswapLDEC:
4311 v = zc_atoi64(str);
4312 break;
4313 case nswapLHEX:
4314 v = zc_xtoi64(str);
4315 break;
4316 case nswapBOOL:
4317 v = d->fg;
4318 break;
4319 }
4320 int32_t b;
4321 if ( v > 2147483647 )
4322 b=2147483647;
4323 else if ( v < INT_MIN )
4324 b=INT_MIN;
4325 else b = (int32_t)v;
4326 bool queued_neg = d->bg;
4327 if(msg==MSG_CHAR && ((c&255)=='-'))
4328 {
4329 if(b)
4330 {
4331 if(b==INT_MIN)
4332 ++b;
4333 b = -b;
4334 v = b;
4335 if(b<0)
4336 {
4337 if(str[0] != '-')
4338 {
4339 char buf[16] = {0};
4340 strcpy(buf, str);
4341 sprintf(str, "-%s", buf);
4342 INC_TF_CURSORS(d->d2,1,strlen(str));
4343 }
4344 }
4345 else if(str[0] == '-')
4346 {
4347 char buf[16] = {0};
4348 strcpy(buf, str);
4349 sprintf(str, "%s", buf+1);
4350 INC_TF_CURSORS(d->d2,-1,strlen(str));
4351 }
4352 if(msg != MSG_DRAW) ret |= D_REDRAWME;
4353 }
4354 else queued_neg = !queued_neg; //queue negative
4355 c &= ~255;
4356 ret |= D_USED_CHAR;
4357 }
4358 if(b && queued_neg)
4359 {
4360 //b = -b; //actually, 'atoi' handles it for us.....
4361 queued_neg = false;
4362 }
4363 if(bool(d->bg) != queued_neg)
4364 {
4365 d->bg = queued_neg;
4366 if(queued_neg)
4367 {
4368 if(str[0] != '-')
4369 {
4370 char buf[16] = {0};
4371 strcpy(buf, str);
4372 sprintf(str, "-%s", buf);
4373 INC_TF_CURSORS(d->d2,1,strlen(str));
4374 }
4375 }
4376 else if(!b && str[0] == '-')
4377 {
4378 char buf[16] = {0};
4379 strcpy(buf, str);
4380 sprintf(str, "%s", buf+1);
4381 INC_TF_CURSORS(d->d2,-1,strlen(str));
4382 }
4383 if(msg != MSG_DRAW) ret |= D_REDRAWME;
4384 }
4385 if(v != b || msg == MSG_START)
4386 {
4387 switch(type)
4388 {
4389 case nswapDEC:
4390 if(b < 0)
4391 sprintf(str, "-%ld.%04ld", abs(b/10000L), abs(b%10000L));
4392 else sprintf(str, "%ld.%04ld", b/10000L, b%10000L);
4393 trim_trailing_0s(str);
4394 break;
4395 case nswapHEX:
4396 if(b<0)
4397 sprintf(str, "-%lX.%04ld", abs(b/10000L), abs(b%10000L));
4398 else sprintf(str, "%lX.%04ld", b/10000L, abs(b%10000L));
4399 trim_trailing_0s(str);
4400 break;
4401 case nswapLDEC:
4402 sprintf(str, "%d", b);
4403 break;
4404 case nswapLHEX:
4405 if(b<0)
4406 sprintf(str, "-%X", -b);
4407 else sprintf(str, "%X", b);
4408 break;
4409 }
4410 d->d2 = 0xFFFF0000|strlen(str);
4411 if(msg != MSG_DRAW) ret |= D_REDRAWME;
4412 }
4413 if(d->fg != b)
4414 {
4415 d->fg = b; //Store numeric data
4416 GUI_EVENT(d, geUPDATE_SWAP);
4417 }
4418 if(msg==MSG_CHAR && ((c&255)=='.'))
4419 {
4420 if(type >= nswapLDEC) //No '.' in long modes
4421 c&=~255;
4422 else
4423 {
4424 for(int32_t q = 0; str[q]; ++q)
4425 {
4426 if(str[q] == '.') //Only one '.'
4427 {
4428 c&=~255;
4429 break;
4430 }
4431 }
4432 }
4433 }
4434 bool rev_d2 = false;
4435 int32_t old_d2 = d->d2;
4436 int32_t ref_d2;
4437 if(msg == MSG_CHAR && queued_neg)
4438 {
4439 auto scursor = d->d2 & 0xFFFF;
4440 auto ecursor = (d->d2 & 0xFFFF0000) >> 16;
4441 if(!scursor)
4442 {
4443 rev_d2 = true;
4444 INC_TF_CURSORS(d->d2,1,strlen(str));
4445 ref_d2 = d->d2;
4446 }
4447 }
4448 bool areaselect = (d->d2 & 0xFFFF0000) != 0xFFFF0000;
4449 switch(type)
4450 {
4451 case nswapDEC:
4452 d->d1 = 12; //12 digits max (incl '-', '.')
4453 if(msg==MSG_CHAR && !editproc_special_key(c) && !areaselect)
4454 {
4455 int32_t p = 0;
4456 for(int32_t q = 0; str[q]; ++q)
4457 {
4458 if(str[q]=='.')
4459 {
4460 if((d->d2&0x0000FFFF) <= q)
4461 break; //typing before the '.'
4462 ++p;
4463 }
4464 else if(p) ++p;
4465 }
4466 if(p>=5) //too many chars after '.'
4467 c&=~255;
4468 }
4469 ret |= jwin_numedit_proc(msg, d, c);
4470 break;
4471 case nswapHEX:
4472 d->d1 = 11; //11 digits max (incl '-', '.')
4473 if(msg==MSG_CHAR && !editproc_special_key(c))
4474 {
4475 if(!((c&255)=='.'||isxdigit(c&255)))
4476 c&=~255;
4477 else if(isxdigit(c&255) && !isdigit(c&255))
4478 for(int32_t q = 0; q < (d->d2&0x0000FFFF) && str[q]; ++q)
4479 {
4480 if(str[q] == '.') //No hex digits to the right of the '.'
4481 {
4482 c&=~255;
4483 break;
4484 }
4485 }
4486 if((c&255) && !areaselect)
4487 {
4488 int32_t p = 0;
4489 for(int32_t q = 0; str[q]; ++q)
4490 {
4491 if(str[q]=='.')
4492 {
4493 if((d->d2&0x0000FFFF) <= q)
4494 break; //typing before the '.'
4495 ++p;
4496 }
4497 else if(p) ++p;
4498 }
4499 if(p>=5) //too many chars after '.'
4500 c&=~255;
4501 }
4502 if(isalpha(c&255)) //always capitalize
4503 c = (c&~255) | (toupper(c&255));
4504 }
4505 ret |= jwin_hexedit_proc(msg, d, c);
4506 break;
4507 case nswapLDEC:
4508 d->d1 = 11; //11 digits max (incl '-')
4509 ret |= jwin_numedit_proc(msg, d, c);
4510 break;
4511 case nswapLHEX:
4512 d->d1 = 9; //9 digits max (incl '-')
4513 if(msg == MSG_CHAR && !editproc_special_key(c) && isalpha(c&255)) //always capitalize
4514 c = (c&~255) | (toupper(c&255));
4515 ret |= jwin_hexedit_proc(msg, d, c);
4516 break;
4517 }
4518 if(rev_d2 && ref_d2 == d->d2)
4519 {
4520 d->d2 = old_d2;
4521 }
4522
4523 if(msg==MSG_START)
4524 tf_obj->refresh_cb_swap();
4525
4526 return ret;
4527 }
4528
4529 /* _calc_scroll_bar:
4530 * Helps find positions of buttons on the scroll bar.
4531 */
4532 void _calc_scroll_bar(int32_t h, int32_t height, int32_t listsize, int32_t offset,
4533 int32_t *bh, int32_t *len, int32_t *pos)
4534 {
4535 *bh = zc_max(zc_min((h-4)/2, 14), 0);
4536 *len = zc_max(((h - 32) * height + listsize/2) / listsize , 6);
4537 *pos = ((h - 32 - *len) * offset) / (listsize-height);
4538 }
4539
4540 /* _handle_scrollable_click:
4541 * Helper to process a click on a scrollable object.
4542 */
4543
4544 void _handle_jwin_scrollable_scroll_click(DIALOG *d, int32_t listsize, int32_t *offset, FONT *fnt)
4545 {
4546 enum { top_btn, bottom_btn, bar, top_bar, bottom_bar };
4547
4548 int32_t xx, yy;
4549 int32_t height = (d->h-3) / (fnt ? text_height(fnt) : 1);
4550 int32_t hh = d->h - 32;
4551 int32_t obj = bar;
4552 int32_t bh, len, pos;
4553 int32_t down = 1, last_draw = 0;
4554 int32_t redraw = 0, mouse_delay = 0;
4555
4556 _calc_scroll_bar(d->h, height, listsize, *offset, &bh, &len, &pos);
4557
4558 xx = d->x + d->w - 18;
4559
4560 // find out which object is being clicked
4561
4562 yy = gui_mouse_y();
4563
4564 if(yy <= d->y+2+bh)
4565 {
4566 obj = top_btn;
4567 yy = d->y+2;
4568 }
4569 else if(yy >= d->y+d->h-2-bh)
4570 {
4571 obj = bottom_btn;
4572 yy = d->y+d->h-2-bh;
4573 }
4574 else if(d->h > 32+6)
4575 {
4576 if(yy < d->y+2+bh+pos)
4577 obj = top_bar;
4578 else if(yy >= d->y+2+bh+pos+len)
4579 obj = bottom_bar;
4580 }
4581
4582 while(gui_mouse_b())
4583 {
4584 _calc_scroll_bar(d->h, height, listsize, *offset, &bh, &len, &pos);
4585
4586 switch(obj)
4587 {
4588 case top_btn:
4589 case bottom_btn:
4590 down = mouse_in_rect(xx, yy, 16, bh);
4591
4592 if(!down)
4593 mouse_delay = 0;
4594 else
4595 {
4596 if((mouse_delay&1)==0)
4597 {
4598 if(obj==top_btn && *offset>0)
4599 {
4600 (*offset)--;
4601 redraw = 1;
4602 }
4603
4604 if(obj==bottom_btn && *offset<listsize-height)
4605 {
4606 (*offset)++;
4607 redraw = 1;
4608 }
4609 }
4610
4611 mouse_delay++;
4612 }
4613
4614 if(down!=last_draw || redraw)
4615 {
4616 vsync();
4617 d->proc(MSG_DRAW, d, 0);
4618 draw_arrow_button(screen, xx, yy, 16, bh, obj==top_btn, down*3);
4619 last_draw = down;
4620 }
4621
4622 break;
4623
4624 case top_bar:
4625 case bottom_bar:
4626 if(mouse_in_rect(xx, d->y+2, 16, d->h-4))
4627 {
4628 if(obj==top_bar)
4629 {
4630 if(gui_mouse_y() < d->y+2+bh+pos)
4631 yy = *offset - height;
4632 }
4633 else
4634 {
4635 if(gui_mouse_y() >= d->y+2+bh+pos+len)
4636 yy = *offset + height;
4637 }
4638
4639 if(yy < 0)
4640 yy = 0;
4641
4642 if(yy > listsize-height)
4643 yy = listsize-height;
4644
4645 if(yy != *offset)
4646 {
4647 *offset = yy;
4648 vsync();
4649 d->proc(MSG_DRAW, d, 0);
4650 }
4651 }
4652
4653 _calc_scroll_bar(d->h, height, listsize, *offset, &bh, &len, &pos);
4654
4655 if(!mouse_in_rect(xx, d->y+2+bh+pos, 16, len))
4656 break;
4657
4658 // fall through
4659
4660 case bar:
4661 default:
4662 xx = gui_mouse_y() - pos;
4663
4664 while(gui_mouse_b())
4665 {
4666 yy = (listsize * (gui_mouse_y() - xx) + hh/2) / hh;
4667
4668 if(yy > listsize-height)
4669 yy = listsize-height;
4670
4671 if(yy < 0)
4672 yy = 0;
4673
4674 bool should_redraw = false;
4675 if(yy != *offset)
4676 {
4677 *offset = yy;
4678 d->proc(MSG_DRAW, d, 0);
4679 should_redraw = true;
4680 }
4681
4682 /* let other objects continue to animate */
4683 int r = broadcast_dialog_message(MSG_IDLE, 0);
4684 if (r & D_REDRAWME) should_redraw = true;
4685
4686 if (should_redraw)
4687 {
4688 update_hw_screen();
4689 }
4690 }
4691
4692 break;
4693
4694 } // switch(obj)
4695
4696 redraw = 0;
4697
4698 update_hw_screen();
4699 // let other objects continue to animate
4700 broadcast_dialog_message(MSG_IDLE, 0);
4701 }
4702
4703 if(last_draw==1)
4704 {
4705 draw_arrow_button(screen, xx, yy, 16, bh, obj==top_btn, 0);
4706 }
4707 }
4708
4709 /* _handle_scrollable_scroll:
4710 * Helper function to scroll through a scrollable object.
4711 */
4712
4713 static void _handle_jwin_scrollable_scroll(DIALOG *d, int32_t listsize, int32_t *index, int32_t *offset, FONT *fnt)
4714 {
4715 int32_t height = (d->h-3) / text_height(fnt);
4716
4717 if(listsize <= 0)
4718 {
4719 *index = *offset = 0;
4720 return;
4721 }
4722
4723 // check selected item
4724 if(*index < 0)
4725 *index = 0;
4726 else if(*index >= listsize)
4727 *index = listsize - 1;
4728
4729 // check scroll position
4730 while((*offset > 0) && (*offset + height > listsize))
4731 (*offset)--;
4732
4733 if(*offset >= *index)
4734 {
4735 if(*index < 0)
4736 *offset = 0;
4737 else
4738 *offset = *index;
4739 }
4740 else
4741 {
4742 while((*offset + height - 1) < *index)
4743 (*offset)++;
4744 }
4745 }
4746
4747 /* idle_cb:
4748 * rest_callback() routine to keep dialogs animating nice and smoothly.
4749 */
4750
4751 static void idle_cb()
4752 {
4753 broadcast_dialog_message(MSG_IDLE, 0);
4754 }
4755
4756 /* _handle_listbox_click:
4757 * Helper to process a click on a listbox, doing hit-testing and moving
4758 * the selection.
4759 */
4760
4761 static bool _handle_jwin_listbox_click(DIALOG *d)
4762 {
4763 ListData *data = (ListData *)d->dp;
4764 char *sel = (char *)d->dp2;
4765 int32_t listsize, height;
4766 int32_t i, j;
4767
4768 data->listFunc(-1, &listsize);
4769
4770 if(!listsize)
4771 return false;
4772
4773 height = (d->h-3) / text_height(*data->font);
4774
4775 i = MID(0, ((gui_mouse_y() - d->y - 4) / text_height(*data->font)),
4776 ((d->h-3) / text_height(*data->font) - 1));
4777 i += d->d2;
4778
4779 if(i < d->d2)
4780 i = d->d2;
4781 else
4782 {
4783 if(i > d->d2 + height-1)
4784 i = d->d2 + height-1;
4785
4786 if(i >= listsize)
4787 i = listsize-1;
4788 }
4789
4790 if(gui_mouse_y() <= d->y)
4791 i = MAX(i-1, 0);
4792 else if(gui_mouse_y() >= d->y+d->h)
4793 i = MIN(i+1, listsize-1);
4794
4795 if(i != d->d1)
4796 {
4797 if(sel)
4798 {
4799 if(key_shifts & (KB_SHIFT_FLAG | KB_CTRL_CMD_FLAG))
4800 {
4801 if((key_shifts & KB_SHIFT_FLAG) || (d->flags & D_INTERNAL))
4802 {
4803 for(j=MIN(i, d->d1); j<=MAX(i, d->d1); j++)
4804 sel[j] = TRUE;
4805 }
4806 else
4807 sel[i] = TRUE;
4808 }
4809 }
4810
4811 d->d1 = i;
4812 i = d->d2;
4813
4814 _handle_jwin_scrollable_scroll(d, listsize, &d->d1, &d->d2, *data->font);
4815
4816 object_message(d, MSG_DRAW, 0);
4817
4818 if(i != d->d2)
4819 rest_callback(MID(10, text_height(font)*16-d->h, 100), idle_cb);
4820 return true;
4821 }
4822 return false;
4823 }
4824
4825 /* _jwin_draw_scrollable_frame:
4826 * Helper function to draw a frame for all objects with vertical scrollbars.
4827 */
4828 void _jwin_draw_scrollable_frame(DIALOG *d, int32_t listsize, int32_t offset, int32_t height, int32_t type)
4829 {
4830 int32_t pos, len;
4831 int32_t xx, yy, hh, bh;
4832 static BITMAP *pattern = NULL; // just create it once
4833
4834 /* draw frame */
4835 if(type)
4836 // for droplists
4837 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, FR_DARK);
4838 else
4839 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, FR_DEEP);
4840
4841 /* possibly draw scrollbar */
4842 if(listsize > height)
4843 {
4844 _calc_scroll_bar(d->h, height, listsize, offset, &bh, &len, &pos);
4845
4846 xx = d->x + d->w - 18;
4847
4848 draw_arrow_button(screen, xx, d->y+2, 16, bh, 1, 0);
4849 draw_arrow_button(screen, xx, d->y+d->h-2-bh, 16, bh, 0, 0);
4850
4851 if(d->h > 32)
4852 {
4853 yy = d->y + 16;
4854 hh = (d->h-32);
4855
4856 /* create and draw the scrollbar */
4857 if(!pattern)
4858 pattern = create_bitmap_ex(bitmap_color_depth(screen),2,2);
4859
4860 putpixel(pattern, 0, 1, scheme[jcLIGHT]);
4861 putpixel(pattern, 1, 0, scheme[jcLIGHT]);
4862 putpixel(pattern, 0, 0, scheme[jcBOX]);
4863 putpixel(pattern, 1, 1, scheme[jcBOX]);
4864
4865 drawing_mode(DRAW_MODE_COPY_PATTERN, pattern, 0, 0);
4866 rectfill(screen, xx, yy, xx+15, yy+hh-1, 0);
4867 solid_mode();
4868
4869 if(d->h > 32+6)
4870 {
4871 jwin_draw_button(screen, xx, yy+pos, 16, len, 0, 1);
4872 }
4873 }
4874
4875 if(d->flags & D_GOTFOCUS)
4876 _dotted_rect(d->x+2, d->y+2, d->x+d->w-19, d->y+d->h-3, scheme[jcTEXTFG], scheme[jcTEXTBG]);
4877 }
4878 else if(d->flags & D_GOTFOCUS)
4879 _dotted_rect(d->x+2, d->y+2, d->x+d->w-3, d->y+d->h-3, scheme[jcTEXTFG], scheme[jcTEXTBG]);
4880 }
4881
4882 /*
4883 Effectively an overload of _jwin_draw_listbox that is used eclusively for file/abc listers.
4884 */
4885 void _jwin_draw_abclistbox(DIALOG *d)
4886 {
4887 int32_t height, listsize, i, len, bar, x, y, w;
4888 int32_t fg_color, bg_color, fg, bg;
4889 char *sel = (char*)d->dp2;
4890 char s[1024] = { 0 };
4891 ListData *data = (ListData *)d->dp;
4892
4893 FONT* oldfont = font;
4894 font = *data->font;
4895
4896 data->listFunc(-1, &listsize);
4897 height = (d->h-3) / text_height(font);
4898 bar = (listsize > height);
4899 w = (bar ? d->w-21 : d->w-5);
4900 rectfill(screen, d->x, d->y, d->x+d->w-1, d->y+d->h+9, scheme[jcBOX]);
4901 fg_color = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : (d->fg ? d->fg : scheme[jcTEXTFG]);
4902 bg_color = (d->flags & D_DISABLED) ? scheme[jcDISABLED_BG] : (d->bg ? d->bg : scheme[jcTEXTBG]);
4903
4904 rectfill(screen, d->x+2, d->y+2, d->x+w+2, d->y+3, bg_color);
4905 vline(screen, d->x+2, d->y+4, d->y+d->h-3, bg_color);
4906 vline(screen, d->x+3, d->y+4, d->y+d->h-3, bg_color);
4907 vline(screen, d->x+w+1, d->y+4, d->y+d->h-3, bg_color);
4908 vline(screen, d->x+w+2, d->y+4, d->y+d->h-3, bg_color);
4909 {
4910 rectfill(screen, d->x+1, d->y+d->h+2, d->x+d->w-2, d->y+1+d->h+text_height(font), bg_color);
4911 strncpy(s, abc_keypresses, 1023);
4912 char* s2 = s;
4913 int32_t tw = (d->w-1);
4914 while(text_length(font, s2) >= tw)
4915 {
4916 ++s2;
4917 }
4918 textout_ex(screen, font, s2, d->x+1, d->y+d->h+2,fg_color, bg_color);
4919 }
4920 //d->flags|=D_DIRTY;
4921
4922 /* draw box contents */
4923 for(i=0; i<height; i++)
4924 {
4925 if(d->d2+i < listsize)
4926 {
4927 if(d->d2+i == d->d1 && !(d->flags & D_DISABLED))
4928 {
4929 fg = scheme[jcSELFG];
4930 bg = scheme[jcSELBG];
4931 }
4932 else if((sel) && (sel[d->d2+i]))
4933 {
4934 fg = scheme[jcDISABLED_FG];
4935 bg = scheme[jcSELBG];
4936 }
4937 else
4938 {
4939 fg = fg_color;
4940 bg = bg_color;
4941 }
4942
4943 strncpy(s, data->listFunc(i+d->d2, NULL), 1023);
4944 x = d->x + 4;
4945 y = d->y + 4 + i*text_height(*data->font);
4946 // text_mode(bg);
4947 rectfill(screen, x, y, x+7, y+text_height(*data->font)-1, bg);
4948 x += 8;
4949 len = (int32_t)strlen(s);
4950
4951 while(text_length(*data->font, s) >= d->w - (bar ? 26 : 10))
4952 {
4953 len--;
4954 s[len] = 0;
4955 }
4956
4957 textout_ex(screen, *data->font, s, x, y, fg,bg);
4958 x += text_length(*data->font, s);
4959
4960 if(x <= d->x+w)
4961 rectfill(screen, x, y, d->x+w, y+text_height(*data->font)-1, bg);
4962 }
4963 else
4964 rectfill(screen, d->x+2, d->y+4+i*text_height(*data->font),
4965 d->x+w+2, d->y+3+(i+1)*text_height(*data->font), bg_color);
4966 }
4967
4968 if(d->y+4+i*text_height(font) <= d->y+d->h-3)
4969 rectfill(screen, d->x+2, d->y+4+i*text_height(*data->font),
4970 d->x+w+2, d->y+d->h-3, bg_color);
4971
4972 /* draw frame, maybe with scrollbar */
4973 _jwin_draw_scrollable_frame(d, listsize, d->d2, height, (d->flags&D_USER)?1:0);
4974
4975 font = oldfont;
4976 }
4977
4978 /* _jwin_draw_listbox:
4979 * Helper function to draw a listbox object.
4980 */
4981 void _jwin_draw_listbox(DIALOG *d)
4982 {
4983 int32_t height, listsize, i, len, bar, x, y, w;
4984 int32_t fg_color, bg_color, fg, bg;
4985 char *sel = (char*)d->dp2;
4986 char s[1024] = {0};
4987 ListData *data = (ListData *)d->dp;
4988
4989 data->listFunc(-1, &listsize);
4990 height = (d->h-3) / text_height(*data->font);
4991 bar = (listsize > height);
4992 w = (bar ? d->w-21 : d->w-5);
4993 fg_color = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : (d->fg ? d->fg : scheme[jcTEXTFG]);
4994 bg_color = (d->flags & D_DISABLED) ? scheme[jcDISABLED_BG] : (d->bg ? d->bg : scheme[jcTEXTBG]);
4995
4996 rectfill(screen, d->x+2, d->y+2, d->x+w+2, d->y+3, bg_color);
4997 vline(screen, d->x+2, d->y+4, d->y+d->h-3, bg_color);
4998 vline(screen, d->x+3, d->y+4, d->y+d->h-3, bg_color);
4999 vline(screen, d->x+w+1, d->y+4, d->y+d->h-3, bg_color);
5000 vline(screen, d->x+w+2, d->y+4, d->y+d->h-3, bg_color);
5001
5002 /* draw box contents */
5003 for(i=0; i<height; i++)
5004 {
5005 if(d->d2+i < listsize)
5006 {
5007 if(d->d2+i == d->d1 && !(d->flags & D_DISABLED))
5008 {
5009 fg = scheme[jcSELFG];
5010 bg = scheme[jcSELBG];
5011 }
5012 else if((sel) && (sel[d->d2+i]))
5013 {
5014 fg = scheme[jcMEDDARK];
5015 bg = scheme[jcSELBG];
5016 }
5017 else
5018 {
5019 fg = fg_color;
5020 bg = bg_color;
5021 }
5022
5023 strncpy(s, data->listFunc(i+d->d2, NULL), 1023);
5024 x = d->x + 4;
5025 y = d->y + 4 + i*text_height(*data->font);
5026 // text_mode(bg);
5027 rectfill(screen, x, y, x+7, y+text_height(*data->font)-1, bg);
5028 x += 8;
5029 len = (int32_t)strlen(s);
5030
5031 while(len > 0 && text_length(*data->font, s) >= d->w - (bar ? 26 : 10))
5032 {
5033 len--;
5034 s[len] = 0;
5035 }
5036
5037 textout_ex(screen, *data->font, s, x, y, fg,bg);
5038 x += text_length(*data->font, s);
5039
5040 if(x <= d->x+w)
5041 rectfill(screen, x, y, d->x+w, y+text_height(*data->font)-1, bg);
5042 }
5043 else
5044 rectfill(screen, d->x+2, d->y+4+i*text_height(*data->font),
5045 d->x+w+2, d->y+3+(i+1)*text_height(*data->font), bg_color);
5046 }
5047
5048 if(d->y+4+i*text_height(font) <= d->y+d->h-3)
5049 rectfill(screen, d->x+2, d->y+4+i*text_height(*data->font),
5050 d->x+w+2, d->y+d->h-3, bg_color);
5051
5052 /* draw frame, maybe with scrollbar */
5053 _jwin_draw_scrollable_frame(d, listsize, d->d2, height, (d->flags&D_USER)?1:0);
5054 }
5055
5056 /* jwin_list_proc:
5057 * A list box object. The dp field points to a ListData struct containing
5058 * a function which it will call
5059 * to obtain information about the list. This should follow the form:
5060 * char *<list_func_name> (int32_t index, int32_t *list_size);
5061 * If index is zero or positive, the function should return a pointer to
5062 * the string which is to be displayed at position index in the list. If
5063 * index is negative, it should return null and list_size should be set
5064 * to the number of items in the list. The list box object will allow the
5065 * user to scroll through the list and to select items list by clicking
5066 * on them, and if it has the input focus also by using the arrow keys. If
5067 * the D_EXIT flag is set, double clicking on a list item will cause it to
5068 * close the dialog. The index of the selected item is held in the d1
5069 * field, and d2 is used to store how far it has scrolled through the list.
5070 */
5071 int32_t jwin_list_proc(int32_t msg, DIALOG *d, int32_t c)
5072 {
5073 ListData *data = (ListData *)d->dp;
5074 int32_t listsize, i, bottom, height, bar, orig;
5075 char *sel = (char *)d->dp2;
5076 int32_t redraw = FALSE;
5077
5078 switch(msg)
5079 {
5080
5081 case MSG_START:
5082 data->listFunc(-1, &listsize);
5083 _handle_jwin_scrollable_scroll(d, listsize, &d->d1, &d->d2, *data->font);
5084 break;
5085
5086 case MSG_DRAW:
5087 _jwin_draw_listbox(d);
5088 break;
5089
5090 case MSG_CLICK:
5091 data->listFunc(-1, &listsize);
5092 height = (d->h-3) / text_height(*data->font);
5093 bar = (listsize > height);
5094
5095 if((!bar) || (gui_mouse_x() < d->x+d->w-18))
5096 {
5097 if((sel) && (!(key_shifts & KB_CTRL_CMD_FLAG)))
5098 {
5099 for(i=0; i<listsize; i++)
5100 {
5101 if(sel[i])
5102 {
5103 redraw = TRUE;
5104 sel[i] = FALSE;
5105 }
5106 }
5107
5108 if(redraw)
5109 {
5110 object_message(d, MSG_DRAW, 0);
5111 }
5112 }
5113
5114 if(_handle_jwin_listbox_click(d)) GUI_EVENT(d, geCHANGE_SELECTION);
5115
5116 bool rightClicked=(gui_mouse_b()&2)!=0;
5117 while(gui_mouse_b())
5118 {
5119 broadcast_dialog_message(MSG_IDLE, 0);
5120 d->flags |= D_INTERNAL;
5121 bool should_redraw = false;
5122 if(_handle_jwin_listbox_click(d))
5123 {
5124 d->flags &= ~D_INTERNAL;
5125 GUI_EVENT(d, geCHANGE_SELECTION);
5126 should_redraw = true;
5127 }
5128 d->flags &= ~D_INTERNAL;
5129
5130 /* let other objects continue to animate */
5131 int r = broadcast_dialog_message(MSG_IDLE, 0);
5132 if (r & D_REDRAWME) should_redraw = true;
5133
5134 if (should_redraw)
5135 {
5136 update_hw_screen();
5137 }
5138 }
5139
5140 if(rightClicked)
5141 {
5142 GUI_EVENT(d, geRCLICK);
5143 if((d->flags&(D_USER<<1))!=0 && d->dp3)
5144 {
5145 typedef void (*funcType)(int32_t /* index */, int32_t /* x */, int32_t /* y */);
5146 funcType func=reinterpret_cast<funcType>(d->dp3);
5147 func(d->d1, gui_mouse_x(), gui_mouse_y());
5148 }
5149 }
5150
5151 if(d->flags & D_USER)
5152 {
5153 if(listsize)
5154 {
5155 clear_keybuf();
5156 return D_CLOSE;
5157 }
5158 }
5159
5160 return D_REDRAWME;
5161 }
5162 else
5163 {
5164 _handle_jwin_scrollable_scroll_click(d, listsize, &d->d2, *data->font);
5165 }
5166
5167 break;
5168
5169 case MSG_DCLICK:
5170 // Ignore double right-click
5171 if((gui_mouse_b()&2)!=0)
5172 break;
5173
5174 data->listFunc(-1, &listsize);
5175 height = (d->h-3) / text_height(*data->font);
5176 bar = (listsize > height);
5177
5178 if((!bar) || (gui_mouse_x() < d->x+d->w-18))
5179 {
5180 if(listsize)
5181 {
5182 i = d->d1;
5183 object_message(d, MSG_CLICK, 0);
5184
5185 if(i == d->d1)
5186 {
5187 if(d->flags & D_EXIT)
5188 return D_CLOSE;
5189 else GUI_EVENT(d, geDCLICK);
5190 }
5191 }
5192 }
5193
5194 break;
5195
5196 case MSG_KEY:
5197 data->listFunc(-1, &listsize);
5198
5199 if((listsize) && (d->flags & D_EXIT))
5200 return D_CLOSE;
5201
5202 break;
5203
5204 case MSG_WANTFOCUS:
5205 return D_WANTFOCUS;
5206
5207 case MSG_WANTWHEEL:
5208 return 1;
5209
5210 case MSG_WHEEL:
5211 data->listFunc(-1, &listsize);
5212 height = (d->h-4) / text_height(*data->font);
5213
5214 if(height < listsize)
5215 {
5216 int32_t delta = (height > 3) ? 3 : 1;
5217
5218 if(c > 0)
5219 {
5220 i = MAX(0, d->d2-delta);
5221 }
5222 else
5223 {
5224 i = MIN(listsize-height, d->d2+delta);
5225 }
5226
5227 if(i != d->d2)
5228 {
5229 d->d2 = i;
5230 object_message(d, MSG_DRAW, 0);
5231 GUI_EVENT(d, geCHANGE_SELECTION);
5232 return D_REDRAWME;
5233 }
5234 }
5235
5236 break;
5237
5238 case MSG_CHAR:
5239 data->listFunc(-1,&listsize);
5240
5241 if(listsize)
5242 {
5243 c >>= 8;
5244
5245 bottom = d->d2 + (d->h-3)/text_height(*data->font) - 1;
5246
5247 if(bottom >= listsize-1)
5248 bottom = listsize-1;
5249
5250 orig = d->d1;
5251
5252 if(c == KEY_UP)
5253 d->d1--;
5254 else if(c == KEY_DOWN)
5255 d->d1++;
5256 else if(c == KEY_HOME)
5257 d->d1 = 0;
5258 else if(c == KEY_END)
5259 d->d1 = listsize-1;
5260 else if(c == KEY_PGUP)
5261 {
5262 if(d->d1 > d->d2)
5263 d->d1 = d->d2;
5264 else
5265 d->d1 -= (bottom - d->d2);
5266 }
5267 else if(c == KEY_PGDN)
5268 {
5269 if(d->d1 < bottom)
5270 d->d1 = bottom;
5271 else
5272 d->d1 += (bottom - d->d2);
5273 }
5274 else
5275 return D_O_K;
5276
5277 if(sel)
5278 {
5279 if(!(key_shifts & (KB_SHIFT_FLAG | KB_CTRL_CMD_FLAG)))
5280 {
5281 for(i=0; i<listsize; i++)
5282 sel[i] = FALSE;
5283 }
5284 else if(key_shifts & KB_SHIFT_FLAG)
5285 {
5286 for(i=MIN(orig, d->d1); i<=MAX(orig, d->d1); i++)
5287 {
5288 if(key_shifts & KB_CTRL_CMD_FLAG)
5289 sel[i] = (i != d->d1);
5290 else
5291 sel[i] = TRUE;
5292 }
5293 }
5294 }
5295
5296 /* if we changed something, better redraw... !Also bounds the index! */
5297 _handle_jwin_scrollable_scroll(d, listsize, &d->d1, &d->d2, *data->font);
5298
5299 GUI_EVENT(d, geCHANGE_SELECTION);
5300
5301 if (d->d1 != orig)
5302 d->flags |= D_DIRTY;
5303 return D_USED_CHAR;
5304 }
5305
5306 break;
5307 }
5308
5309 return D_O_K;
5310 }
5311
5312
5313 /*
5314 Effectively an overload of jwin_list_proc that i used eclusively for abc lists.
5315 This calls the appropriate form of drawing for those listers.
5316 */
5317 int32_t jwin_do_abclist_proc(int32_t msg, DIALOG *d, int32_t c)
5318 {
5319 ListData *data = (ListData *)d->dp;
5320 int32_t listsize, i, bottom, height, bar, orig, h;
5321 int32_t ret = D_O_K;
5322 bool revert_size = false;
5323 if((d->flags & D_RESIZED) == 0)
5324 {
5325 h = d->h;
5326 d->h -= text_height(*data->font);
5327 d->flags |= D_RESIZED;
5328 revert_size = true;
5329 }
5330 char *sel = (char *)d->dp2;
5331 int32_t redraw = FALSE;
5332
5333 switch(msg)
5334 {
5335
5336 case MSG_START:
5337 data->listFunc(-1, &listsize);
5338 _handle_jwin_scrollable_scroll(d, listsize, &d->d1, &d->d2, *data->font);
5339 break;
5340
5341 case MSG_DRAW:
5342 _jwin_draw_abclistbox(d);
5343 break;
5344
5345 case MSG_CLICK:
5346 if(gui_mouse_y() > (d->y+d->h-1))
5347 {
5348 if(gui_mouse_y() > (d->y+d->h+2))
5349 {
5350 //Clicked on the box displaying the patternmatch
5351 }
5352 else {} //Clicked between the lister and patternmatch
5353 }
5354 else //Clicked the lister
5355 {
5356 data->listFunc(-1, &listsize);
5357 height = (d->h-3) / text_height(*data->font);
5358 bar = (listsize > height);
5359
5360 if((!bar) || (gui_mouse_x() < d->x+d->w-18))
5361 {
5362 if((sel) && (!(key_shifts & KB_CTRL_CMD_FLAG)))
5363 {
5364 for(i=0; i<listsize; i++)
5365 {
5366 if(sel[i])
5367 {
5368 redraw = TRUE;
5369 sel[i] = FALSE;
5370 }
5371 }
5372
5373 if(redraw)
5374 {
5375 object_message(d, MSG_DRAW, 0);
5376 }
5377 }
5378
5379 if(_handle_jwin_listbox_click(d)) GUI_EVENT(d, geCHANGE_SELECTION);
5380
5381 bool rightClicked=(gui_mouse_b()&2)!=0;
5382 while(gui_mouse_b())
5383 {
5384 broadcast_dialog_message(MSG_IDLE, 0);
5385 d->flags |= D_INTERNAL;
5386 if(_handle_jwin_listbox_click(d))
5387 {
5388 d->flags &= ~D_INTERNAL;
5389 GUI_EVENT(d, geCHANGE_SELECTION);
5390 update_hw_screen();
5391 }
5392 d->flags &= ~D_INTERNAL;
5393 rest(1);
5394 }
5395
5396 if(rightClicked)
5397 {
5398 GUI_EVENT(d, geRCLICK);
5399 if((d->flags&(D_USER<<1))!=0 && d->dp3)
5400 {
5401 typedef void (*funcType)(int32_t /* index */, int32_t /* x */, int32_t /* y */);
5402 funcType func=reinterpret_cast<funcType>(d->dp3);
5403 func(d->d1, gui_mouse_x(), gui_mouse_y());
5404 }
5405 }
5406
5407 if(d->flags & D_USER)
5408 {
5409 if(listsize)
5410 {
5411 clear_keybuf();
5412 ret = D_CLOSE;
5413 }
5414 }
5415
5416 return D_REDRAWME;
5417 }
5418 else
5419 {
5420 _handle_jwin_scrollable_scroll_click(d, listsize, &d->d2, *data->font);
5421 }
5422 }
5423 break;
5424
5425 case MSG_DCLICK:
5426 // Ignore double right-click
5427 if((gui_mouse_b()&2)!=0)
5428 break;
5429
5430 if(gui_mouse_y() > (d->y+d->h-1))
5431 {
5432 if(gui_mouse_y() > (d->y+d->h+2))
5433 {
5434 //Clicked on the box displaying the patternmatch
5435 }
5436 else {} //Clicked between the lister and patternmatch
5437 }
5438 else //Clicked the lister
5439 {
5440 data->listFunc(-1, &listsize);
5441 height = (d->h-3) / text_height(*data->font);
5442 bar = (listsize > height);
5443
5444 if((!bar) || (gui_mouse_x() < d->x+d->w-18))
5445 {
5446 if(listsize)
5447 {
5448 i = d->d1;
5449 object_message(d, MSG_CLICK, 0);
5450
5451 if(i == d->d1)
5452 {
5453 if(d->flags & D_EXIT)
5454 ret = D_CLOSE;
5455 else GUI_EVENT(d, geDCLICK);
5456 }
5457 }
5458 }
5459 }
5460 break;
5461
5462 case MSG_KEY:
5463 data->listFunc(-1, &listsize);
5464
5465 if((listsize) && (d->flags & D_EXIT))
5466 ret = D_CLOSE;
5467
5468 break;
5469
5470 case MSG_WANTFOCUS:
5471 ret = D_WANTFOCUS;
5472 break;
5473
5474 case MSG_WANTWHEEL:
5475 return 1;
5476
5477 case MSG_WHEEL:
5478 data->listFunc(-1, &listsize);
5479 height = (d->h-4) / text_height(*data->font);
5480
5481 if(height < listsize)
5482 {
5483 int32_t delta = (height > 3) ? 3 : 1;
5484
5485 if(c > 0)
5486 {
5487 i = MAX(0, d->d2-delta);
5488 }
5489 else
5490 {
5491 i = MIN(listsize-height, d->d2+delta);
5492 }
5493
5494 if(i != d->d2)
5495 {
5496 d->d2 = i;
5497 object_message(d, MSG_DRAW, 0);
5498 GUI_EVENT(d, geCHANGE_SELECTION);
5499 ret |= D_REDRAWME;
5500 }
5501 }
5502
5503 break;
5504
5505 case MSG_CHAR:
5506 data->listFunc(-1,&listsize);
5507
5508 if(listsize)
5509 {
5510 c >>= 8;
5511
5512 bottom = d->d2 + (d->h-3)/text_height(*data->font) - 1;
5513
5514 if(bottom >= listsize-1)
5515 bottom = listsize-1;
5516
5517 orig = d->d1;
5518
5519 if(c == KEY_UP)
5520 d->d1--;
5521 else if(c == KEY_DOWN)
5522 d->d1++;
5523 else if(c == KEY_HOME)
5524 d->d1 = 0;
5525 else if(c == KEY_END)
5526 d->d1 = listsize-1;
5527 else if(c == KEY_PGUP)
5528 {
5529 if(d->d1 > d->d2)
5530 d->d1 = d->d2;
5531 else
5532 d->d1 -= (bottom - d->d2);
5533 }
5534 else if(c == KEY_PGDN)
5535 {
5536 if(d->d1 < bottom)
5537 d->d1 = bottom;
5538 else
5539 d->d1 += (bottom - d->d2);
5540 }
5541 else
5542 break; //return D_O_K;
5543
5544 if(sel)
5545 {
5546 if(!(key_shifts & (KB_SHIFT_FLAG | KB_CTRL_CMD_FLAG)))
5547 {
5548 for(i=0; i<listsize; i++)
5549 sel[i] = FALSE;
5550 }
5551 else if(key_shifts & KB_SHIFT_FLAG)
5552 {
5553 for(i=MIN(orig, d->d1); i<=MAX(orig, d->d1); i++)
5554 {
5555 if(key_shifts & KB_CTRL_CMD_FLAG)
5556 sel[i] = (i != d->d1);
5557 else
5558 sel[i] = TRUE;
5559 }
5560 }
5561 }
5562
5563 /* if we changed something, better redraw... */
5564 _handle_jwin_scrollable_scroll(d, listsize, &d->d1, &d->d2, *data->font);
5565
5566 GUI_EVENT(d, geCHANGE_SELECTION);
5567
5568 if (d->d1 != orig)
5569 d->flags |= D_DIRTY;
5570 ret = D_USED_CHAR;
5571 }
5572
5573 break;
5574 }
5575 if(revert_size)
5576 {
5577 d->h = h;
5578 d->flags &= ~D_RESIZED;
5579 }
5580 return ret;
5581 }
5582
5583 /* _jwin_draw_textbox:
5584 * Helper function to draw a textbox object.
5585 */
5586 void _jwin_draw_textbox(char *thetext, int32_t *listsize, int32_t draw, int32_t offset,
5587 int32_t wword, int32_t tabsize, int32_t x, int32_t y, int32_t w, int32_t h,
5588 int32_t disabled)
5589 {
5590 int32_t fg = scheme[jcTEXTFG];
5591 int32_t bg = scheme[jcTEXTBG];
5592 int32_t y1 = y+4;
5593 int32_t x1;
5594 int32_t len;
5595 int32_t ww = w-10;
5596 char s[16] = {0};
5597 char text[16] = {0};
5598 char space[16] = {0};
5599 char *printed = text;
5600 char *scanned = text;
5601 char *oldscan = text;
5602 char *ignore = NULL;
5603 char *tmp, *ptmp;
5604 int32_t width;
5605 int32_t line = 0;
5606 int32_t i = 0;
5607 int32_t noignore;
5608 // int32_t rtm;
5609
5610 usetc(s+usetc(s, '.'), 0);
5611 usetc(text+usetc(text, ' '), 0);
5612 usetc(space+usetc(space, ' '), 0);
5613
5614 /* find the correct text */
5615 if(thetext != NULL)
5616 {
5617 printed = thetext;
5618 scanned = thetext;
5619 }
5620
5621 /* choose the text color */
5622 if(disabled)
5623 {
5624 fg = scheme[jcDISABLED_FG];
5625 bg = scheme[jcDISABLED_BG];
5626 }
5627
5628 /* do some drawing setup */
5629 if(draw)
5630 {
5631 /* initial start blanking at the top */
5632 rectfill(screen, x+2, y+2, x+w-2, y1-1, bg);
5633 }
5634
5635 // rtm = text_mode(bg);
5636
5637 /* loop over the entire string */
5638 for(;;)
5639 {
5640 width = 0;
5641
5642 /* find the next break */
5643 while(ugetc(scanned))
5644 {
5645 /* check for a forced break */
5646 if(ugetc(scanned) == '\n')
5647 {
5648 scanned += uwidth(scanned);
5649
5650 /* we are done parsing the line end */
5651 break;
5652 }
5653
5654 /* the next character length */
5655 usetc(s+usetc(s, ugetc(scanned)), 0);
5656 len = text_length(font, s);
5657
5658 /* modify length if its a tab */
5659 if(ugetc(s) == '\t')
5660 len = tabsize * text_length(font, space);
5661
5662 /* check for the end of a line by excess width of next char */
5663 if(width+len >= ww)
5664 {
5665 /* we have reached end of line do we go back to find start */
5666 if(wword)
5667 {
5668 /* remember where we were */
5669 oldscan = scanned;
5670 noignore = FALSE;
5671
5672 /* go backwards looking for start of word */
5673 while(!uisspace(ugetc(scanned)))
5674 {
5675 /* don't wrap too far */
5676 if(scanned == printed)
5677 {
5678 /* the whole line is filled, so stop here */
5679 tmp = ptmp = scanned;
5680
5681 while(ptmp != oldscan)
5682 {
5683 ptmp = tmp;
5684 tmp += uwidth(tmp);
5685 }
5686
5687 scanned = ptmp;
5688 noignore = TRUE;
5689 break;
5690 }
5691
5692 /* look further backwards to wrap */
5693 tmp = ptmp = printed;
5694
5695 while(tmp < scanned)
5696 {
5697 ptmp = tmp;
5698 tmp += uwidth(tmp);
5699 }
5700
5701 scanned = ptmp;
5702 }
5703
5704 /* put the space at the end of the line */
5705 if(!noignore)
5706 {
5707 ignore = scanned;
5708 scanned += uwidth(scanned);
5709 }
5710 else
5711 ignore = NULL;
5712
5713 /* check for endline at the convenient place */
5714 if(ugetc(scanned) == '\n')
5715 scanned += uwidth(scanned);
5716 }
5717
5718 /* we are done parsing the line end */
5719 break;
5720 }
5721
5722 /* the character can be added */
5723 scanned += uwidth(scanned);
5724 width += len;
5725 }
5726
5727 /* check if we are to print it */
5728 if((draw) && (line >= offset) && (y1+text_height(font) < (y+h-3)))
5729 {
5730 x1 = x+4;
5731
5732 /* the initial blank bit */
5733 rectfill(screen, x+2, y1, x1-1, y1+text_height(font), bg);
5734
5735 /* print up to the marked character */
5736 while(printed != scanned)
5737 {
5738 /* do special stuff for each character */
5739 switch(ugetc(printed))
5740 {
5741
5742 case '\r':
5743 case '\n':
5744 /* don't print endlines in the text */
5745 break;
5746
5747 /* possibly expand the tabs */
5748 case '\t':
5749 for(i=0; i<tabsize; i++)
5750 {
5751 usetc(s+usetc(s, ' '), 0);
5752 textout_ex(screen, font, s, x1, y1, fg,bg);
5753 x1 += text_length(font, s);
5754 }
5755
5756 break;
5757
5758 /* print a normal character */
5759 default:
5760 if(printed != ignore)
5761 {
5762 usetc(s+usetc(s, ugetc(printed)), 0);
5763 textout_ex(screen, font, s, x1, y1, fg,bg);
5764 x1 += text_length(font, s);
5765 }
5766 }
5767
5768 /* goto the next character */
5769 printed += uwidth(printed);
5770 }
5771
5772 /* the last blank bit */
5773 if(x1 <= x+w-3)
5774 rectfill(screen, x1, y1, x+w-2, y1+text_height(font)-1, bg);
5775
5776 /* print the line end */
5777 y1 += text_height(font);
5778 }
5779
5780 printed = scanned;
5781
5782 /* we have done a line */
5783 line++;
5784
5785 /* check if we are at the end of the string */
5786 if(!ugetc(printed))
5787 {
5788 /* the under blank bit */
5789 if(draw)
5790 rectfill(screen, x+1, y1, x+w-2, y+h-1, bg);
5791
5792 /* tell how many lines we found */
5793 *listsize = line;
5794 // text_mode(rtm);
5795 return;
5796 }
5797 }
5798
5799 // text_mode(rtm);
5800 }
5801
5802 /* jwin_textbox_proc:
5803 * A text box object. The dp field points to a char * which is the text
5804 * to be displayed in the text box. If the text is long, there will be
5805 * a vertical scrollbar on the right hand side of the object which can
5806 * be used to scroll through the text. The default is to print the text
5807 * with word wrapping, but if the D_SELECTED flag is set, the text will
5808 * be printed with character wrapping. The d1 field is used internally
5809 * to store the number of lines of text, and d2 is used to store how far
5810 * it has scrolled through the text.
5811 */
5812 int32_t jwin_textbox_proc(int32_t msg, DIALOG *d, int32_t c)
5813 {
5814 int32_t height, bar, ret = D_O_K;
5815 int32_t start, top, bottom,l;
5816 int32_t used, delta;
5817 // int32_t fg_color = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : d->fg;
5818
5819 FONT *oldfont=NULL;
5820
5821 if(d->dp2!=NULL)
5822 {
5823 oldfont=font;
5824 font=(FONT*)d->dp2;
5825 }
5826
5827 /* calculate the actual height */
5828 height = (d->h-4) / text_height(font);
5829
5830 switch(msg)
5831 {
5832
5833 case MSG_START:
5834 /* measure how many lines of text we contain */
5835 _jwin_draw_textbox((char*)d->dp, &d->d1,
5836 0, /* DONT DRAW anything */
5837 d->d2, !(d->flags & D_SELECTED), 8,
5838 d->x, d->y, d->w, d->h,
5839 (d->flags & D_DISABLED));
5840 break;
5841
5842 case MSG_DRAW:
5843 /* tell the object to sort of draw, but only calculate the listsize */
5844 _jwin_draw_textbox((char*)d->dp, &d->d1,
5845 0, /* DONT DRAW anything */
5846 d->d2, !(d->flags & D_SELECTED), 8,
5847 d->x, d->y, d->w, d->h,
5848 (d->flags & D_DISABLED));
5849
5850 if(d->d1 > height)
5851 {
5852 bar = 16;
5853 }
5854 else
5855 {
5856 bar = 0;
5857 d->d2 = 0;
5858 }
5859
5860 /* now do the actual drawing */
5861 _jwin_draw_textbox((char*)d->dp, &d->d1, 1, d->d2,
5862 !(d->flags & D_SELECTED), 8,
5863 d->x, d->y, d->w-bar-1, d->h,
5864 (d->flags & D_DISABLED));
5865
5866 /* draw the frame around */
5867 _jwin_draw_scrollable_frame(d, d->d1, d->d2, height, 0);
5868 break;
5869
5870 case MSG_CLICK:
5871 /* figure out if it's on the text or the scrollbar */
5872 bar = (d->d1 > height);
5873
5874 if((!bar) || (gui_mouse_x() < d->x+d->w-18))
5875 {
5876 /* clicked on the text area */
5877 ret = D_O_K;
5878 }
5879 else
5880 {
5881 /* clicked on the scroll area */
5882 _handle_jwin_scrollable_scroll_click(d, d->d1, &d->d2, font);
5883 }
5884
5885 break;
5886
5887 case MSG_WANTWHEEL:
5888 return 1;
5889
5890 case MSG_WHEEL:
5891 l = (d->h-8)/text_height(font);
5892 delta = (l > 3) ? 3 : 1;
5893
5894 // scroll, making sure that the list stays in bounds
5895 start = d->d2;
5896 d->d2 = (c > 0) ? MAX(0, d->d2-delta) : MIN(d->d1-l, d->d2+delta);
5897
5898 // if we changed something, better redraw...
5899 if(d->d2 != start)
5900 {
5901 d->flags |= D_DIRTY;
5902 }
5903
5904 ret = D_O_K;
5905 break;
5906
5907 case MSG_CHAR:
5908 start = d->d2;
5909 used = D_USED_CHAR;
5910
5911 if(d->d1 > 0)
5912 {
5913 if(d->d2 > 0)
5914 top = d->d2+1;
5915 else
5916 top = 0;
5917
5918 l = (d->h-3)/text_height(font);
5919
5920 bottom = d->d2 + l - 1;
5921
5922 if(bottom >= d->d1-1)
5923 bottom = d->d1-1;
5924 else
5925 bottom--;
5926
5927 if((c>>8) == KEY_UP)
5928 d->d2--;
5929 else if((c>>8) == KEY_DOWN)
5930 d->d2++;
5931 else if((c>>8) == KEY_HOME)
5932 d->d2 = 0;
5933 else if((c>>8) == KEY_END)
5934 d->d2 = d->d1-l;
5935 else if((c>>8) == KEY_PGUP)
5936 d->d2 = d->d2-(bottom-top);
5937 else if((c>>8) == KEY_PGDN)
5938 d->d2 = d->d2+(bottom-top);
5939 else
5940 used = D_O_K;
5941
5942 /* make sure that the list stays in bounds */
5943 if(d->d2 > d->d1-l)
5944 d->d2 = d->d1-l;
5945
5946 if(d->d2 < 0)
5947 d->d2 = 0;
5948 }
5949 else
5950 used = D_O_K;
5951
5952 /* if we changed something, better redraw... */
5953 if(d->d2 != start)
5954 {
5955 d->proc(MSG_DRAW, d, 0);
5956 }
5957
5958 ret = used;
5959 break;
5960
5961 case MSG_WANTFOCUS:
5962
5963 /* if we don't have a scrollbar we can't do anything with the focus */
5964 if(d->d1 > height)
5965 ret = D_WANTFOCUS;
5966
5967 break;
5968
5969 default:
5970 ret = D_O_K;
5971 }
5972
5973 if(d->dp2!=NULL)
5974 {
5975 font=oldfont;
5976 }
5977
5978 return ret;
5979 }
5980
5981 /* jwin_slider_proc:
5982 * A slider control object. This object returns a value in d2, in the
5983 * range from 0 to d1. It will display as a vertical slider if h is
5984 * greater than or equal to w; otherwise, it will display as a horizontal
5985 * slider. dp can contain an optional bitmap to use for the slider handle;
5986 * dp2 can contain an optional callback function, which is called each
5987 * time d2 changes. The callback function should have the following
5988 * prototype:
5989 *
5990 * int32_t function(void *dp3, int32_t d2);
5991 *
5992 * The d_slider_proc object will return the value of the callback function.
5993 */
5994 int32_t jwin_slider_proc(int32_t msg, DIALOG *d, int32_t c)
5995 {
5996 BITMAP *slhan = NULL;
5997 int32_t sfg; /* slider foreground color */
5998 int32_t vert = TRUE; /* flag: is slider vertical? */
5999 int32_t hh = 7; /* handle height (width for horizontal sliders) */
6000 int32_t hmar; /* handle margin */
6001 int32_t slp; /* slider position */
6002 int32_t irange;
6003 int32_t slx, sly, slh, slw;
6004 fixed slratio, slmax, slpos;
6005 ASSERT(d);
6006
6007 /* check for slider direction */
6008 if(d->h < d->w)
6009 {
6010 vert = FALSE;
6011 }
6012
6013 /* set up the metrics for the control */
6014 if(d->dp != NULL)
6015 {
6016 slhan = (BITMAP *)d->dp;
6017
6018 if(vert)
6019 {
6020 hh = slhan->h;
6021 }
6022 else
6023 {
6024 hh = slhan->w;
6025 }
6026 }
6027
6028 hmar = hh/2;
6029 irange = (vert) ? d->h : d->w;
6030 slmax = itofix(irange-hh);
6031 slratio = slmax / (d->d1);
6032 slpos = slratio * d->d2;
6033 slp = fixtoi(slpos);
6034
6035 switch(msg)
6036 {
6037 case MSG_DRAW:
6038 // sfg = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : scheme[jcBOXFG];
6039 sfg = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : scheme[jcBOXFG];
6040
6041 if(vert)
6042 {
6043 rectfill(screen, d->x, d->y, d->x+d->w/2-2, d->y+d->h, scheme[jcBOX]);
6044 rectfill(screen, d->x+d->w/2-1, d->y, d->x+d->w/2+1, d->y+d->h, sfg);
6045 rectfill(screen, d->x+d->w/2+2, d->y, d->x+d->w, d->y+d->h, scheme[jcBOX]);
6046 }
6047 else
6048 {
6049 rectfill(screen, d->x, d->y, d->x+d->w, d->y+d->h/2-2, scheme[jcBOX]);
6050 rectfill(screen, d->x, d->y+d->h/2-1, d->x+d->w, d->y+d->h/2+1, sfg);
6051 rectfill(screen, d->x, d->y+d->h/2+2, d->x+d->w, d->y+d->h, scheme[jcBOX]);
6052 }
6053
6054 if(d->flags & D_GOTFOCUS)
6055 {
6056 _dotted_rect(d->x, d->y, d->x+d->w, d->y+d->h, sfg, scheme[jcBOX]);
6057 }
6058
6059 /* okay, background and slot are drawn, now draw the handle */
6060 if(slhan)
6061 {
6062 if(vert)
6063 {
6064 slx = d->x+(d->w/2)-(slhan->w/2);
6065 sly = d->y+d->h-(hh+slp);
6066 }
6067 else
6068 {
6069 slx = d->x+slp;
6070 sly = d->y+(d->h/2)-(slhan->h/2);
6071 }
6072
6073 draw_sprite(screen, slhan, slx, sly);
6074 }
6075 else
6076 {
6077 /* draw default handle */
6078 if(vert)
6079 {
6080 slx = d->x;
6081 sly = d->y+d->h-(hh+slp);
6082 slw = d->w;
6083 slh = hh;
6084 }
6085 else
6086 {
6087 slx = d->x+slp;
6088 sly = d->y;
6089 slw = hh;
6090 slh = d->h;
6091 }
6092
6093 jwin_draw_button(screen, slx, sly, slw+1, slh+1, d->flags&D_DISABLED?3:0, 0);
6094 }
6095
6096 break;
6097
6098 default:
6099 return d_jslider_proc(msg, d, c);
6100 }
6101
6102 return D_O_K;
6103 }
6104
6105 const char* rowpref(int32_t row, bool alt)
6106 {
6107 static const char *lcol = "Level Colors", *syscol = "System Colors", *bosscol = "Boss Colors", *thmcol = "Theme Colors", *nlcol="";
6108 switch(row)
6109 {
6110 case 2: case 3: case 4: case 9:
6111 return lcol;
6112 case 14:
6113 return alt ? syscol : bosscol;
6114 case 15:
6115 return thmcol;
6116 default:
6117 return nlcol;
6118 }
6119 }
6120
6121 byte getHighlightColor(int32_t c)
6122 {
6123 RGB col;
6124 get_color(c, &col);
6125 return getHighlightColor(col);
6126 }
6127
6128 byte getHighlightColor(RGB const& col)
6129 {
6130 double lum = (pow(col.r/64.0, 2.2) * 0.2126) +
6131 (pow(col.g/64.0, 2.2) * 0.7152) +
6132 (pow(col.b/64.0, 2.2) * 0.0722);
6133 return lum < 0.4 ? vc(15) : vc(0);
6134 //Old -Em
6135 // byte bright = (col.r >= 32) + (col.g >= 32) + (col.b >= 32);
6136 // byte sbright = (col.r >= 48) + (col.g >= 48) + (col.b >= 48);
6137 // byte highlightColor = vc(7); //sysgray
6138 // if(bright >= 2)
6139 // {
6140 // if(sbright >= 2)
6141 // highlightColor = vc(0); //sysblack
6142 // else highlightColor = vc(8); //sysdarkgray
6143 // }
6144 // else if(!bright)
6145 // highlightColor = vc(15); //syswhite
6146 // return highlightColor;
6147 }
6148
6149 int32_t jwin_selcolor_proc(int32_t msg, DIALOG *d, int32_t c)
6150 {
6151 int32_t ret = D_O_K;
6152 if(!d->d2) d->d2 = 12;
6153 bool alt = d->d2 > 16;
6154 int32_t numcsets = alt ? 16 : d->d2;
6155 int32_t numcol = numcsets*0x10;
6156 if(msg==MSG_START)
6157 {
6158 d->w = d->h = (16*8) * 1.5;
6159 }
6160 int32_t csz = 12;
6161 d->w = csz * 16;
6162 d->h = csz * numcsets;
6163 switch(msg)
6164 {
6165 case MSG_DRAW:
6166 {
6167 jwin_draw_frame(screen, d->x-2, d->y-2, d->w+4, d->h+4, FR_ETCHED);
6168 for(int32_t c = 0; c < numcol; ++c)
6169 {
6170 int32_t x = (c%16)*csz, y = (c/16)*csz;
6171 rectfill(screen, d->x+x, d->y+y, d->x+x+csz-1, d->y+y+csz-1, c);
6172 if(c == d->d1)
6173 {
6174 byte highlightColor = getHighlightColor(c);
6175 rect(screen, d->x+x+0, d->y+y+0, d->x+x+csz-1, d->y+y+csz-1, highlightColor);
6176 rect(screen, d->x+x+1, d->y+y+1, d->x+x+csz-2, d->y+y+csz-2, highlightColor);
6177 }
6178 }
6179
6180 FONT *oldfont = font;
6181
6182 if(d->dp2)
6183 {
6184 font = (FONT*)d->dp2;
6185 }
6186
6187 char buf[32]={0};
6188 for(int32_t col = 0; col < 16; ++col)
6189 {
6190 sprintf(buf, "%X", col);
6191 gui_textout_ln(screen, (uint8_t*)buf, d->x + (csz*col) + (csz/2), d->y-3-text_height(font), scheme[jcBOXFG], scheme[jcBOX], 1);
6192 }
6193 for(int32_t row = 0; row < numcsets; ++row)
6194 {
6195 sprintf(buf, "%s 0x%02X", rowpref(row, alt), row*16);
6196 gui_textout_ln(screen, (uint8_t*)buf, d->x-3, d->y + (csz*row) + (csz-text_height(font))/2, scheme[jcBOXFG], scheme[jcBOX], 2);
6197 }
6198
6199 font = oldfont;
6200 break;
6201 }
6202
6203 case MSG_CLICK:
6204 {
6205 if(mouse_in_rect(d->x, d->y, d->x+d->w-1, d->y+d->h-1))
6206 {
6207 int32_t col = ((gui_mouse_x() - d->x) / csz) + 16*((gui_mouse_y() - d->y) / csz);
6208
6209 if(col>-1 && col != d->d1)
6210 {
6211 d->d1 = col;
6212 ret |= D_REDRAWME;
6213 }
6214 ret |= D_WANTFOCUS;
6215 }
6216 break;
6217 }
6218
6219 case MSG_WANTFOCUS:
6220 case MSG_LOSTFOCUS:
6221 case MSG_KEY:
6222 ret = D_WANTFOCUS;
6223 break;
6224
6225 case MSG_CHAR:
6226 {
6227 ret = D_USED_CHAR | D_REDRAWME;
6228 switch(c>>8)
6229 {
6230 case KEY_LEFT:
6231 {
6232 if(d->d1 % 0x10)
6233 --d->d1;
6234 break;
6235 }
6236 case KEY_RIGHT:
6237 {
6238 if(d->d1 % 0x10 != 0x0F)
6239 ++d->d1;
6240 break;
6241 }
6242 case KEY_UP:
6243 {
6244 if(d->d1 / 0x10)
6245 d->d1 -= 0x10;
6246 break;
6247 }
6248 case KEY_DOWN:
6249 {
6250 if(d->d1 / 0x10 != numcsets)
6251 d->d1 += 0x10;
6252 break;
6253 }
6254 case KEY_ENTER:
6255 {
6256 ret = D_CLOSE;
6257 break;
6258 }
6259 default: ret = D_O_K;
6260 }
6261 break;
6262 }
6263 }
6264 return ret;
6265 }
6266
6267 static DIALOG selcolor_dlg[] =
6268 {
6269 { jwin_win_proc, 0, 0, 306, 63+16*8, vc(14), vc(1), 0, D_EXIT, 0, 0, (void *)"Select Color", NULL, NULL },
6270 { jwin_button_proc, 75, 40+16*8, 61, 21, vc(14), vc(1), 0, D_EXIT, 0, 0, (void *)"OK", NULL, NULL },
6271 { jwin_button_proc, 164, 40+16*8, 61, 21, vc(14), vc(1), 0, D_EXIT, 0, 0, (void *)"Cancel", NULL, NULL },
6272 { jwin_selcolor_proc, 156-64, 34, 16*8, 16*8, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6273
6274 { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
6275 };
6276
6277 int32_t jwin_color_swatch(int32_t msg, DIALOG *d, int32_t c)
6278 {
6279 int32_t ret = D_O_K;
6280
6281 switch(msg)
6282 {
6283 case MSG_START:
6284 {
6285 if(d->d2 < 1) d->d2 = 12;
6286 else if(d->d2 > 17) d->d2 = 17;
6287 break;
6288 }
6289
6290 case MSG_DRAW:
6291 {
6292 if(!d->d1 || (d->flags&D_DISABLED))
6293 {
6294 rectfill(screen, d->x, d->y, d->x+d->w-1, d->y+d->h-1,
6295 (d->flags&D_DISABLED) ? scheme[jcDISABLED_BG] : vc(0));
6296 line(screen, d->x, d->y, d->x+d->w-1, d->y+d->h-1, vc(15));
6297 line(screen, d->x, d->y+d->h-1, d->x+d->w-1, d->y, vc(15));
6298 jwin_draw_frame(screen, d->x-2, d->y-2, d->w+4, d->h+4, FR_DEEP);
6299 }
6300 else
6301 {
6302 int32_t c;
6303 switch(d->d1) //special cases
6304 {
6305 case BLACK:
6306 c = vc(0);
6307 break;
6308 case WHITE:
6309 c = vc(15);
6310 break;
6311 default:
6312 c = d->d1;
6313 break;
6314 }
6315 rectfill(screen, d->x, d->y, d->x+d->w-1, d->y+d->h-1, c);
6316 jwin_draw_frame(screen, d->x-2, d->y-2, d->w+4, d->h+4, FR_ETCHED);
6317 }
6318 break;
6319 }
6320
6321 case MSG_CLICK:
6322 {
6323 if(d->flags&(D_READONLY|D_DISABLED)) break;
6324 selcolor_dlg[0].dp2 = get_zc_font(font_lfont);
6325 selcolor_dlg[3].bg = scheme[jcBOXFG];
6326 selcolor_dlg[3].fg = scheme[jcBOX];
6327 selcolor_dlg[3].d1 = d->d1;
6328 selcolor_dlg[3].d2 = d->d2;
6329 large_dialog(selcolor_dlg);
6330
6331 while(gui_mouse_b()) rest(1); //wait for mouseup
6332
6333 //!TODO Move this out of jwin, and do better palette management.
6334 //!TODO Allow loading different level palettes, sprite palettes, etc via buttons
6335 PALETTE oldpal;
6336 get_palette(oldpal);
6337 bool alt = d->d2 > 16;
6338 if(!alt)
6339 {
6340 PALETTE foopal;
6341 get_palette(foopal);
6342 foopal[BLACK] = _RGB(0,0,0);
6343 foopal[WHITE] = _RGB(255,255,255);
6344 zc_set_palette(foopal);
6345 }
6346
6347 jwin_center_dialog(selcolor_dlg);
6348 int32_t val = do_zqdialog(selcolor_dlg, 3);
6349 ret = D_REDRAW;
6350
6351 zc_set_palette(oldpal);
6352 if(val == 1 || val == 3)
6353 {
6354 d->d1 = selcolor_dlg[3].d1;
6355 GUI_EVENT(d, geCHANGE_VALUE);
6356 ret |= D_REDRAWME;
6357 }
6358 if(d->flags & D_EXIT)
6359 return D_CLOSE;
6360 break;
6361 }
6362 }
6363 return ret;
6364 }
6365
6366 static DIALOG alert_dialog[] =
6367 {
6368 /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */
6369 { jwin_win_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6370 { d_ctext2_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6371 { d_ctext2_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6372 { d_ctext2_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6373 { jwin_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6374 { jwin_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6375 { jwin_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6376 { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
6377 };
6378
6379 #define A_S1 1
6380 #define A_S2 2
6381 #define A_S3 3
6382 #define A_B1 4
6383 #define A_B2 5
6384 #define A_B3 6
6385
6386 /* jwin_alert3:
6387 * Displays a simple alert box, containing three lines of text (s1-s3),
6388 * and with either one, two, or three buttons. The text for these buttons
6389 * is passed in b1, b2, and b3 (NULL for buttons which are not used), and
6390 * the keyboard shortcuts in c1 and c2. Returns 1, 2, or 3 depending on
6391 * which button was selected.
6392 */
6393 int32_t jwin_alert3(const char *title, const char *s1, const char *s2, const char *s3, const char *b1, const char *b2, const char *b3, int32_t c1, int32_t c2, int32_t c3, FONT *title_font)
6394 {
6395 int32_t maxlen = 0;
6396 int32_t len1, len2, len3;
6397 int32_t avg_w = text_length(font, " ");
6398 int32_t avg_h = text_height(font)+1;
6399 int32_t buttons = 0;
6400 int32_t yofs = (title ? 22 : 0);
6401 int32_t b[3];
6402 int32_t c;
6403
6404 #define SORT_OUT_BUTTON(x) { \
6405 if (b##x) \
6406 { \
6407 alert_dialog[A_B##x].flags &= ~D_HIDDEN; \
6408 alert_dialog[A_B##x].key = c##x; \
6409 alert_dialog[A_B##x].dp = (void *)b##x; \
6410 len##x = gui_strlen(b##x); \
6411 b[buttons++] = A_B##x; \
6412 } \
6413 else \
6414 { \
6415 alert_dialog[A_B##x].flags |= D_HIDDEN; \
6416 len##x = 0; \
6417 } \
6418 }
6419
6420 if(title_font)
6421 {
6422 alert_dialog[0].dp2=title_font;
6423 }
6424
6425 alert_dialog[A_S1].dp = alert_dialog[A_S2].dp = alert_dialog[A_S3].dp =
6426 alert_dialog[A_B1].dp = alert_dialog[A_B2].dp = (void*)"";
6427
6428 if(s1)
6429 {
6430 alert_dialog[A_S1].dp = (void *)s1;
6431 maxlen = text_length(font, s1);
6432 }
6433
6434 if(s2)
6435 {
6436 alert_dialog[A_S2].dp = (void *)s2;
6437 len1 = text_length(font, s2);
6438
6439 if(len1 > maxlen)
6440 maxlen = len1;
6441 }
6442
6443 if(s3)
6444 {
6445 alert_dialog[A_S3].dp = (void *)s3;
6446 len1 = text_length(font, s3);
6447
6448 if(len1 > maxlen)
6449 maxlen = len1;
6450 }
6451
6452 SORT_OUT_BUTTON(1);
6453 SORT_OUT_BUTTON(2);
6454 SORT_OUT_BUTTON(3);
6455
6456 len1 = MAX(len1, MAX(len2, len3)) + avg_w*3;
6457
6458 if(len1*buttons > maxlen)
6459 maxlen = len1*buttons;
6460
6461 maxlen += avg_w*4;
6462 maxlen=zc_max(text_length(title_font?title_font:font,title)+29,maxlen);
6463 alert_dialog[0].w = maxlen;
6464 alert_dialog[A_S1].x = alert_dialog[A_S2].x = alert_dialog[A_S3].x =
6465 alert_dialog[0].x + maxlen/2;
6466
6467 alert_dialog[A_B1].w = alert_dialog[A_B2].w = alert_dialog[A_B3].w = len1;
6468
6469 alert_dialog[A_B1].x = alert_dialog[A_B2].x = alert_dialog[A_B3].x =
6470 alert_dialog[0].x + maxlen/2 - len1/2;
6471
6472 if(buttons == 3)
6473 {
6474 alert_dialog[b[0]].x = alert_dialog[0].x + maxlen/2 - len1*3/2 - avg_w;
6475 alert_dialog[b[2]].x = alert_dialog[0].x + maxlen/2 + len1/2 + avg_w;
6476 }
6477 else if(buttons == 2)
6478 {
6479 alert_dialog[b[0]].x = alert_dialog[0].x + maxlen/2 - len1 - avg_w;
6480 alert_dialog[b[1]].x = alert_dialog[0].x + maxlen/2 + avg_w;
6481 }
6482
6483 alert_dialog[0].h = avg_h*7 + 13 + yofs;
6484 alert_dialog[A_S1].y = alert_dialog[0].y + avg_h + yofs;
6485 alert_dialog[A_S2].y = alert_dialog[0].y + avg_h*2 + yofs;
6486 alert_dialog[A_S3].y = alert_dialog[0].y + avg_h*3 + yofs;
6487 alert_dialog[A_S1].h = alert_dialog[A_S2].h = alert_dialog[A_S3].h = avg_h;
6488
6489 alert_dialog[A_B1].y = alert_dialog[A_B2].y = alert_dialog[A_B3].y =
6490 alert_dialog[0].y + avg_h*5 + yofs;
6491
6492 alert_dialog[A_B1].h = alert_dialog[A_B2].h = alert_dialog[A_B3].h = avg_h+13;
6493
6494 alert_dialog[0].dp = (void *)title;
6495 alert_dialog[0].flags = (title) ? D_EXIT : 0;
6496
6497 jwin_center_dialog(alert_dialog);
6498 set_dialog_color(alert_dialog, scheme[jcTEXTFG], scheme[jcBOX]);
6499
6500 clear_keybuf();
6501
6502 do
6503 {
6504 rest(1);
6505 }
6506 while(gui_mouse_b());
6507
6508 large_dialog(alert_dialog);
6509 alert_dialog[0].d1 = 0;
6510
6511 c = do_zqdialog(alert_dialog, A_B1);
6512
6513 if(c == A_B1)
6514 return 1;
6515 else if(c == A_B2)
6516 return 2;
6517 else
6518 return 3;
6519 }
6520
6521 /* jwin_alert:
6522 * Displays a simple alert box, containing three lines of text (s1-s3),
6523 * and with either one or two buttons. The text for these buttons is passed
6524 * in b1 and b2 (b2 may be null), and the keyboard shortcuts in c1 and c2.
6525 * Returns 1 or 2 depending on which button was selected.
6526 */
6527 int32_t jwin_alert(const char *title, const char *s1, const char *s2, const char *s3, const char *b1, const char *b2, int32_t c1, int32_t c2, FONT *title_font)
6528 {
6529 int32_t ret;
6530
6531 ret = jwin_alert3(title, s1, s2, s3, b1, b2, NULL, c1, c2, 0, title_font);
6532
6533 if(ret > 2)
6534 ret = 2;
6535
6536 return ret;
6537 }
6538
6539 int32_t d_autotext_proc(int32_t msg, DIALOG *d, int32_t c)
6540 {
6541 ASSERT(d);
6542 ASSERT(d->dp);
6543 #define AUTOBUF_SIZE 8092
6544 static char auto_buf[AUTOBUF_SIZE] = {0};
6545 static int32_t auto_inds[50] = {0};
6546
6547
6548 FONT *oldfont = font;
6549
6550 if (d->dp2)
6551 font = (FONT*)d->dp2;
6552 switch(msg)
6553 {
6554 case MSG_START:
6555 {
6556 memset(auto_buf, 0, AUTOBUF_SIZE);
6557 memset(auto_inds, 0, 50);
6558 char* str = (char*)d->dp;
6559 int32_t len = strlen(str);
6560 int32_t pos = 0, curstrpos = 0, linecount = 1, lastWS = -1;
6561 BITMAP* dummy = create_bitmap_ex(8,8,8);
6562 for(int32_t q = 0; q < len; ++q)
6563 {
6564 switch(str[q])
6565 {
6566 case ' ': case '\t':
6567 lastWS = pos;
6568 break;
6569 case '\n': //Forced newline
6570 auto_inds[linecount++] = ++pos;
6571 curstrpos = pos;
6572 lastWS = -1;
6573 continue; //skip rest of for loop, go to next char
6574 }
6575 auto_buf[pos++] = str[q];
6576 if(gui_textout_ex(dummy,auto_buf+curstrpos,0,0,0,0,0) >= d->w) //too int32_t, wrap to lower line
6577 {
6578 if(lastWS<0)
6579 {
6580 auto_buf[pos-1] = 0;
6581 auto_inds[linecount++] = pos;
6582 curstrpos = pos;
6583 auto_buf[pos++] = str[q];
6584 }
6585 else
6586 {
6587 auto_buf[lastWS] = 0;
6588 auto_inds[linecount++] = lastWS+1;
6589 curstrpos = lastWS+1;
6590 if(gui_textout_ex(dummy,auto_buf+curstrpos,0,0,0,0,0) >= d->w) //STILL too int32_t?
6591 {
6592 auto_buf[pos-1] = 0;
6593 auto_inds[linecount++] = pos;
6594 curstrpos = pos;
6595 auto_buf[pos++] = str[q];
6596 }
6597 lastWS = -1;
6598 }
6599 }
6600 }
6601 destroy_bitmap(dummy);
6602 d->d2 = linecount;
6603 d->h = ((text_height(font) + d->d1) * linecount) - d->d1;
6604 }
6605 break;
6606
6607 case MSG_DRAW:
6608 {
6609 int32_t fg = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : d->fg;
6610 int32_t linecount = d->d2;
6611
6612 int32_t yinc = text_height(font)+d->d1;
6613 int32_t y = d->y;
6614 for(int32_t q = 0; q < linecount; ++q)
6615 {
6616 gui_textout_ex(screen, auto_buf+auto_inds[q], d->x, y, fg, d->bg, true);
6617 y += yinc;
6618 }
6619 }
6620 break;
6621 }
6622 font = oldfont;
6623 return D_O_K;
6624 }
6625
6626 static DIALOG alert2_dialog[] =
6627 {
6628 /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */
6629 { jwin_win_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6630 { d_autotext_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6631 { jwin_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6632 { jwin_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6633 { jwin_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6634 { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
6635 };
6636
6637 #define A2_S1 1
6638 #define A2_B1 2
6639 #define A2_B2 3
6640 #define A2_B3 4
6641
6642 /* jwin_auto_alert3:
6643 * Displays a simple alert box, containing one line of text, auto-split
6644 * across lines using 'lenlim' and 'vspace,
6645 * and with either one, two, or three buttons. The text for these buttons
6646 * is passed in b1, b2, and b3 (NULL for buttons which are not used), and
6647 * the keyboard shortcuts in c1 and c2. Returns 1, 2, or 3 depending on
6648 * which button was selected.
6649 */
6650 int32_t jwin_auto_alert3(const char *title, const char *s1, int32_t lenlim, int32_t vspace, const char *b1, const char *b2, const char *b3, int32_t c1, int32_t c2, int32_t c3, FONT *title_font)
6651 {
6652 int32_t maxlen = 0;
6653 int32_t len1, len2, len3;
6654 int32_t avg_w = text_length(font, " ");
6655 int32_t avg_h = text_height(font)+1;
6656 int32_t buttons = 0;
6657 int32_t yofs = (title ? 22 : 0);
6658 int32_t b[3];
6659 int32_t c;
6660
6661 #define SORT_OUT_AUTOBUTTON(x) { \
6662 if (b##x) \
6663 { \
6664 alert2_dialog[A2_B##x].flags &= ~D_HIDDEN; \
6665 alert2_dialog[A2_B##x].key = c##x; \
6666 alert2_dialog[A2_B##x].dp = (void *)b##x; \
6667 len##x = gui_strlen(b##x); \
6668 b[buttons++] = A2_B##x; \
6669 } \
6670 else \
6671 { \
6672 alert2_dialog[A2_B##x].flags |= D_HIDDEN; \
6673 len##x = 0; \
6674 } \
6675 }
6676
6677 if(title_font)
6678 {
6679 alert2_dialog[0].dp2=title_font;
6680 }
6681
6682 alert2_dialog[A2_S1].dp = alert2_dialog[A2_B1].dp = alert2_dialog[A2_B2].dp = (void*)"";
6683
6684 if(s1)
6685 {
6686 alert2_dialog[A2_S1].dp = (void *)s1;
6687 maxlen = lenlim;
6688 }
6689
6690 SORT_OUT_AUTOBUTTON(1);
6691 SORT_OUT_AUTOBUTTON(2);
6692 SORT_OUT_AUTOBUTTON(3);
6693
6694 len1 = MAX(len1, MAX(len2, len3)) + avg_w*3;
6695
6696 if(len1*buttons > maxlen)
6697 maxlen = len1*buttons;
6698
6699 maxlen += avg_w*4;
6700 maxlen=zc_max(text_length(title_font?title_font:font,title)+29,maxlen);
6701
6702 alert2_dialog[A2_S1].x = alert2_dialog[0].x + maxlen/2;
6703 alert2_dialog[A2_S1].y = alert2_dialog[0].y + avg_h + yofs;
6704 alert2_dialog[A2_S1].w = lenlim;
6705 alert2_dialog[A2_S1].d1 = vspace;
6706
6707 large_dialog(alert2_dialog);
6708 alert2_dialog[0].d1 = 0;
6709
6710 object_message(&alert2_dialog[A2_S1], MSG_START, 0); //calculate height
6711
6712 alert2_dialog[A2_S1].x = alert2_dialog[0].x + maxlen/2;
6713 alert2_dialog[A2_S1].y = alert2_dialog[0].y + avg_h + yofs;
6714 alert2_dialog[A2_S1].w = lenlim;
6715 alert2_dialog[A2_S1].d1 = vspace;
6716
6717 alert2_dialog[A2_B1].w = alert2_dialog[A2_B2].w = alert2_dialog[A2_B3].w = len1;
6718
6719 alert2_dialog[A2_B1].x = alert2_dialog[A2_B2].x = alert2_dialog[A2_B3].x =
6720 alert2_dialog[0].x + maxlen/2 - len1/2;
6721
6722 if(buttons == 3)
6723 {
6724 alert2_dialog[b[0]].x = alert2_dialog[0].x + maxlen/2 - len1*3/2 - avg_w;
6725 alert2_dialog[b[2]].x = alert2_dialog[0].x + maxlen/2 + len1/2 + avg_w;
6726 }
6727 else if(buttons == 2)
6728 {
6729 alert2_dialog[b[0]].x = alert2_dialog[0].x + maxlen/2 - len1 - avg_w;
6730 alert2_dialog[b[1]].x = alert2_dialog[0].x + maxlen/2 + avg_w;
6731 }
6732
6733 alert2_dialog[0].w = maxlen;
6734 alert2_dialog[0].h = avg_h*4 + yofs + alert2_dialog[A2_S1].h + 13;
6735 alert2_dialog[A2_B1].y = alert2_dialog[A2_B2].y = alert2_dialog[A2_B3].y =
6736 alert2_dialog[0].y + avg_h*2 + yofs + alert2_dialog[A2_S1].h;
6737
6738 alert2_dialog[A2_B1].h = alert2_dialog[A2_B2].h = alert2_dialog[A2_B3].h = avg_h+13;
6739
6740 alert2_dialog[0].dp = (void *)title;
6741 alert2_dialog[0].flags = (title) ? D_EXIT : 0;
6742
6743 jwin_center_dialog(alert2_dialog);
6744 set_dialog_color(alert2_dialog, scheme[jcTEXTFG], scheme[jcBOX]);
6745
6746 clear_keybuf();
6747
6748 do
6749 {
6750 rest(1);
6751 }
6752 while(gui_mouse_b());
6753
6754 large_dialog(alert2_dialog);
6755 alert2_dialog[0].d1 = 0;
6756
6757 c = do_zqdialog(alert2_dialog, A2_B1);
6758
6759 if(c == A2_B1)
6760 return 1;
6761 else if(c == A2_B2)
6762 return 2;
6763 else
6764 return 3;
6765 }
6766
6767 int32_t jwin_auto_alert(const char *title, const char *s1, int32_t lenlim, int32_t vspace, const char *b1, const char *b2, int32_t c1, int32_t c2, FONT *title_font)
6768 {
6769 int32_t ret;
6770
6771 ret = jwin_auto_alert3(title, s1, lenlim, vspace, b1, b2, NULL, c1, c2, 0, title_font);
6772
6773 if(ret > 2)
6774 ret = 2;
6775
6776 return ret;
6777 }
6778
6779 int32_t last_droplist_sel = -1;
6780 static int32_t d_dropcancel_proc(int32_t msg,DIALOG *d,int32_t c)
6781 {
6782 //these are here to bypass compiler warnings about unused arguments
6783 d=d;
6784 c=c;
6785
6786 if(msg==MSG_CLICK || msg==MSG_DCLICK)
6787 return D_CLOSE;
6788
6789 return D_O_K;
6790 }
6791
6792 static DIALOG droplist_dlg[] =
6793 {
6794 /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3)*/
6795 { d_dropcancel_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6796 { d_list_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6797 { d_keyboard_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_ESC, (void*)close_dlg, NULL, NULL },
6798 { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
6799 };
6800
6801 static int32_t droplist(DIALOG *d)
6802 {
6803 ListData *data = (ListData *)d->dp;
6804 int32_t d1 = d->d1;
6805 int32_t listsize, x, y, w, h, max_w;
6806 auto oz = gui_mouse_z();
6807
6808 data->listFunc(-1, &listsize);
6809 y = d->y + d->h;
6810 h = zc_min(abc_patternmatch ? listsize+1 : listsize,8) * text_height(*data->font) + 8;
6811
6812 if(y+h >= zq_screen_h)
6813 {
6814 y = d->y - h;
6815 }
6816
6817 x = d->x;
6818 w = d->w;
6819 max_w = zc_max(d->x+d->w, zq_screen_w-d->x);
6820
6821 for(int32_t i=0; i<listsize; ++i)
6822 {
6823 w=zc_min(max_w,zc_max(w,text_length(*data->font,data->listFunc(i, NULL))+39));
6824 }
6825
6826 if(x+w >= zq_screen_w)
6827 {
6828 x=zq_screen_w-w;
6829 }
6830
6831 droplist_dlg[1] = *d;
6832 droplist_dlg[1].proc = &jwin_abclist_proc;
6833 droplist_dlg[1].flags = D_EXIT + D_USER;
6834 droplist_dlg[1].x = x;
6835 droplist_dlg[1].y = y;
6836 droplist_dlg[1].w = w;
6837 droplist_dlg[1].h = h;
6838 droplist_dlg[1].d2 = listsize<=8 ? 0 : zc_max(d1-3,0);
6839
6840 // cancel
6841 droplist_dlg[0].x = 0;
6842 droplist_dlg[0].y = 0;
6843 droplist_dlg[0].w = zq_screen_w;
6844 droplist_dlg[0].h = zq_screen_h;
6845
6846 if(do_zq_subdialog(droplist_dlg,1)==1)
6847 {
6848 position_mouse_z(oz);
6849 return droplist_dlg[1].d1;
6850 }
6851
6852 position_mouse_z(oz);
6853 return d1;
6854 }
6855
6856 /* jwin_droplist_proc:
6857 * A drop list...
6858 */
6859 int32_t jwin_droplist_proc(int32_t msg,DIALOG *d,int32_t c)
6860 {
6861 int32_t ret;
6862 int32_t down=0, last_draw=0;
6863 int32_t d1;
6864
6865 switch(msg)
6866 {
6867 case MSG_CLICK:
6868 if(mouse_in_rect(d->x+d->w-18,d->y+2,16,d->h))
6869 goto dropit;
6870
6871 break;
6872
6873 case MSG_KEY:
6874 goto dropit;
6875 break;
6876 }
6877
6878 d1 = d->d1;
6879 ret = jwin_list_proc(msg,d,c);
6880
6881 if(d->d1!=d->d2)
6882 {
6883 d->d1=d->d2;
6884 jwin_droplist_proc(MSG_DRAW, d, 0);
6885 }
6886
6887 if(d1 != d->d1)
6888 {
6889 GUI_EVENT(d, geCHANGE_SELECTION);
6890 if(d->flags&D_EXIT)
6891 ret |= D_CLOSE;
6892 }
6893
6894 if(msg == MSG_DRAW)
6895 {
6896 draw_arrow_button(screen, d->x+d->w-18, d->y+2,16, d->h-4, 0, 0);
6897 }
6898
6899 return ret;
6900
6901 dropit:
6902 last_draw = 0;
6903
6904 while(gui_mouse_b())
6905 {
6906 down = mouse_in_rect(d->x+d->w-18,d->y+2,16,d->h);
6907
6908 if(down!=last_draw)
6909 {
6910 draw_arrow_button(screen, d->x+d->w-18, d->y+2,16, d->h-4, 0, down*3);
6911 last_draw = down;
6912 update_hw_screen();
6913 }
6914
6915 clear_keybuf();
6916 rest(1);
6917 }
6918
6919 if(!down)
6920 {
6921 return D_O_K;
6922 }
6923
6924 draw_arrow_button(screen, d->x+d->w-18, d->y+2,16, d->h-4, 0, 0);
6925
6926 d1 = d->d1;
6927 d->d2 = d->d1 = droplist(d);
6928
6929 object_message(d, MSG_DRAW, 0);
6930
6931 while(gui_mouse_b())
6932 {
6933 clear_keybuf();
6934 rest(1);
6935 update_hw_screen();
6936 }
6937
6938 if(d1!=d->d1)
6939 GUI_EVENT(d, geCHANGE_SELECTION);
6940
6941 return ((d1 != d->d1) && (d->flags&D_EXIT)) ? D_CLOSE : D_O_K;
6942 }
6943
6944
6945 int32_t jwin_abclist_proc(int32_t msg,DIALOG *d,int32_t c)
6946 {
6947 ListData *data = (ListData *)d->dp;
6948 if(msg == MSG_START) wipe_abc_keypresses();
6949
6950 if(msg == MSG_CHAR && (key_shifts&KB_CTRL_CMD_FLAG))
6951 return D_O_K;
6952
6953 if(abc_patternmatch) // Search style pattern match.
6954 {
6955 if(msg==MSG_CHAR && ((c&0xFF) > 31) && ((c&0xFF) < 127)) //(isalpha(c&0xFF) || isdigit(c&0xFF)))
6956 {
6957 int32_t max,dummy,h;
6958
6959 h = ((d->h-3) / text_height(*data->font))-1;
6960 if ( isalpha(c&0xFF) ) c = toupper(c&0xFF);
6961 for ( int32_t q = 0; q < 1023; ++q )
6962 {
6963 if ( !(abc_keypresses[q]) )
6964 {
6965 abc_keypresses[q] = (char)c;
6966 break;
6967 }
6968 }
6969 data->listFunc(-1, &max);
6970
6971 int32_t cur = d->d1;
6972 int32_t charpos = 0; int32_t listpos = 0; int32_t lastmatch = -1;
6973 char tmp[1024] = { 0 };
6974 char lsttmp[1024] = { 0 };
6975 int32_t lastmatches[32768] = {0};
6976 for ( int32_t a = 0; a < 32768; ++a ) lastmatches[a] = -1;
6977 int32_t lmindx = 0;
6978
6979 bool foundmatch = false;
6980 bool numsearch = true;
6981 for ( int32_t q = 0; q < 1023; ++q )
6982 {
6983 if(!abc_keypresses[q]) break;
6984 if(!isdigit(abc_keypresses[q]))
6985 {
6986 if(q == 0 && abc_keypresses[q] == '-')
6987 continue;
6988 numsearch = false;
6989 break;
6990 }
6991 }
6992 if(numsearch) //Indexed search, first
6993 {
6994 int32_t num = atoi(abc_keypresses);
6995 //Find a different indexing type in the strings?
6996 if(!foundmatch)
6997 {
6998 char buf[16];
6999 if(num < 0) sprintf(buf, "(%04d)", num);
7000 else sprintf(buf, "(%03d)", num);
7001 std::string cmp = buf;
7002 for(int32_t listpos = 0; listpos < max; ++listpos)
7003 {
7004 std::string str((data->listFunc(listpos,&dummy)));
7005 size_t trimpos = str.find_last_not_of("-(0123456789)");
7006 if(trimpos != std::string::npos) ++trimpos;
7007 str.erase(0, trimpos);
7008 if(cmp == str)
7009 {
7010 d->d1 = listpos;
7011 d->d2 = zc_max(zc_min(listpos-(h>>1), max-h), 0);
7012 foundmatch = true;
7013 break;
7014 }
7015 }
7016 }
7017 //Search for match with first number in string?
7018 if(!foundmatch)
7019 {
7020 auto buf = fmt::format("{}", num);
7021 for(int32_t listpos = 0; listpos < max; ++listpos)
7022 {
7023 std::string str((data->listFunc(listpos,&dummy)));
7024 size_t pos1 = -1;
7025 do
7026 {
7027 pos1 = str.find_first_of("-0123456789", pos1+1);
7028 } while(pos1 != string::npos && str[pos1] == '-' && pos1+1 < str.size() && !isdigit(str[pos1+1]));
7029 if(pos1 == string::npos)
7030 continue;
7031 size_t pos2 = str.find_first_not_of("-0123456789", pos1);
7032 if(pos2 == string::npos)
7033 continue;
7034 str = str.substr(pos1,pos2-pos1);
7035 if(buf == str)
7036 {
7037 d->d1 = listpos;
7038 d->d2 = zc_max(zc_min(listpos-(h>>1), max-h), 0);
7039 foundmatch = true;
7040 break;
7041 }
7042 }
7043 }
7044 }
7045 if(!foundmatch)
7046 {
7047 strcpy(tmp, abc_keypresses);
7048 for ( int32_t listpos = 0; listpos < max; ++listpos )
7049 {
7050 memset(lsttmp, 0, 1024);
7051 strcpy(lsttmp, ((data->listFunc(listpos,&dummy))));
7052
7053 if ( !(strnicmp(lsttmp, tmp, strlen(tmp))))
7054 {
7055 d->d1 = listpos;
7056 d->d2 = zc_max(zc_min(listpos-(h>>1), max-h), 0);
7057 foundmatch = true;
7058 break;
7059 }
7060 }
7061 }
7062 if(foundmatch)
7063 GUI_EVENT(d, geCHANGE_SELECTION);
7064 d->flags |= D_DIRTY;
7065 if ( gui_mouse_b() ) wipe_abc_keypresses();
7066 return foundmatch ? D_USED_CHAR : D_O_K;
7067 }
7068 else if(msg==MSG_CHAR && ( (c&0xFF) == 8) )//backspace
7069 {
7070 for ( int32_t q = 1023; q >= 0; --q )
7071 {
7072 if ( abc_keypresses[q] )
7073 {
7074 d->flags |= D_DIRTY;
7075 abc_keypresses[q] = '\0'; break;
7076 }
7077 }
7078 return D_USED_CHAR;
7079 }
7080 if ( gui_mouse_b() ) { wipe_abc_keypresses(); }
7081 }
7082 else // Windows Explorer style jumping
7083 {
7084 if(msg==MSG_CHAR && (isalpha(c&0xFF) || isdigit(c&0xFF)))
7085 {
7086 int32_t max,dummy,h,i;
7087
7088 h = (d->h-3) / text_height(*data->font);
7089 c = toupper(c&0xFF);
7090
7091 data->listFunc(-1, &max);
7092
7093 int32_t cur = d->d1;
7094 bool foundmatch = false;
7095 for(i=cur+1; (cur ? (i != cur) : (cur < max)); ++i) //don't infinite loop this.
7096 {
7097 if(i>=max) i=0;
7098 if(toupper((data->listFunc(i,&dummy))[0]) == c)
7099 {
7100 d->d1 = i;
7101 d->d2 = zc_max(zc_min(i-(h>>1), max-h), 0);
7102 foundmatch = true;
7103 break;
7104 }
7105 }
7106
7107 d->flags |= D_DIRTY;
7108 return foundmatch ? D_USED_CHAR : D_O_K;
7109 }
7110 }
7111 if ( gui_mouse_b() ) { wipe_abc_keypresses(); }
7112 return ((abc_patternmatch) ? jwin_do_abclist_proc(msg,d,c) : jwin_list_proc(msg,d,c));
7113 }
7114
7115 int32_t jwin_checkfont_proc(int32_t msg, DIALOG *d, int32_t c)
7116 {
7117
7118 FONT *oldfont = font;
7119
7120 if(d->dp2)
7121 {
7122 font = (FONT *)d->dp2;
7123 }
7124
7125 int32_t rval = jwin_check_proc(msg, d, c);
7126 font = oldfont;
7127 return rval;
7128 }
7129
7130 /* jwin_check_proc:
7131 * Who needs C++ after all? This is derived from d_button_proc,
7132 * but overrides the drawing routine to provide a check box.
7133 */
7134 int32_t jwin_check_proc(int32_t msg, DIALOG *d, int32_t c)
7135 {
7136 //these are here to bypass compiler warnings about unused arguments
7137 c=c;
7138 int32_t x;
7139 int32_t bx=0, tl=0;
7140 int32_t tx=d->x;
7141 ASSERT(d);
7142
7143 switch(msg)
7144 {
7145 case MSG_DRAW:
7146 x = d->x;
7147
7148 if(!(d->d1))
7149 {
7150 if(d->dp)
7151 {
7152 if(d->flags & D_DISABLED)
7153 {
7154 gui_textout_ln(screen, (uint8_t *)d->dp, tx+1, d->y+1+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcLIGHT], scheme[jcBOX], 0);
7155 tl=gui_textout_ln(screen, (uint8_t *)d->dp, tx, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcDISABLED_FG], -1, 0);
7156 bx=tl+text_height(font)/2;
7157 }
7158 else
7159 {
7160 tl=gui_textout_ln(screen, (uint8_t *)d->dp, tx, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcBOXFG], scheme[jcBOX], 0);
7161 bx=tl+text_height(font)/2;
7162 }
7163 }
7164 }
7165
7166 jwin_draw_frame(screen, x+bx, d->y, d->h, d->h, FR_DEEP);
7167
7168 if(!(d->flags & D_DISABLED))
7169 {
7170 rectfill(screen, x+bx+2, d->y+2, x+bx+d->h-3, d->y+d->h-3, scheme[jcTEXTBG]);
7171 }
7172
7173 if(d->d1)
7174 {
7175 tx=x+bx+d->h-1+(text_height(font)/2);
7176
7177 if(d->dp)
7178 {
7179 if(d->flags & D_DISABLED)
7180 {
7181 gui_textout_ln(screen, (uint8_t *)d->dp, tx+1, d->y+1+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcLIGHT], scheme[jcBOX], 0);
7182 tl=gui_textout_ln(screen, (uint8_t *)d->dp, tx, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcDISABLED_FG], -1, 0);
7183 }
7184 else
7185 {
7186 tl=gui_textout_ln(screen, (uint8_t *)d->dp, tx, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcBOXFG], scheme[jcBOX], 0);
7187 }
7188 }
7189 }
7190
7191 if(d->flags & D_SELECTED)
7192 {
7193 line(screen, x+bx+2, d->y+2, x+bx+d->h-3, d->y+d->h-3, scheme[jcTEXTFG]);
7194 line(screen, x+bx+2, d->y+d->h-3, x+bx+d->h-3, d->y+2, scheme[jcTEXTFG]);
7195 }
7196
7197 d->w=int32_t(text_height(font)*1.5);
7198
7199 if(d->dp)
7200 {
7201 // dotted_rect(screen, tx-1, d->y-1, tx+tl, d->y+d->h-1, (d->flags & D_GOTFOCUS)?scheme[jcDARK]:scheme[jcBOX], scheme[jcBOX]);
7202 dotted_rect(screen, tx-1, d->y-1, tx+tl, d->y+(text_height(font)), (d->flags & D_GOTFOCUS)?scheme[jcDARK]:scheme[jcBOX], scheme[jcBOX]);
7203 d->w+=tl+1;
7204 }
7205
7206 return D_O_K;
7207 break;
7208 }
7209
7210 return d_jwinbutton_proc(msg, d, 0);
7211 }
7212
7213 int32_t new_check_proc(int32_t msg, DIALOG *d, int32_t)
7214 {
7215 int32_t bx=0, tl=0;
7216 ASSERT(d);
7217
7218 FONT *oldfont = font;
7219 uint8_t* str = (uint8_t*)d->dp;
7220 bool has_text = str && str[0];
7221 if(d->dp2)
7222 {
7223 font = (FONT *)d->dp2;
7224 }
7225 switch(msg)
7226 {
7227 case MSG_DRAW:
7228 {
7229 const int box_spacing = 4;
7230 int32_t tx = 2, ty = 2, tx2 = 2;
7231 int fh = text_height(font);
7232 auto txt_y = ty+(d->h-fh)/2;
7233 BITMAP* tmp = create_bitmap_ex(8, d->w+4, d->h+4);
7234 clear_bitmap(tmp);
7235 set_clip_rect(tmp, tx, ty, tmp->w-tx, tmp->h-ty);
7236 if(!(d->d1))
7237 {
7238 if(has_text)
7239 {
7240 if(d->flags & D_DISABLED)
7241 {
7242 gui_textout_ln(tmp, str, tx+1, txt_y+1, scheme[jcLIGHT], scheme[jcBOX], 0);
7243 tl=gui_textout_ln(tmp, str, tx, txt_y, scheme[jcDISABLED_FG], -1, 0);
7244 bx=tl+box_spacing;
7245 }
7246 else
7247 {
7248 tl=gui_textout_ln(tmp, str, tx, txt_y, scheme[jcBOXFG], scheme[jcBOX], 0);
7249 bx=tl+box_spacing;
7250 }
7251 }
7252 }
7253
7254 jwin_draw_frame(tmp, tx+bx, ty, d->h, d->h, FR_DEEP);
7255
7256 if(!(d->flags & D_DISABLED))
7257 {
7258 rectfill(tmp, tx+bx+2, ty+2, tx+bx+d->h-3, ty+d->h-3, scheme[jcTEXTBG]);
7259 }
7260
7261 if(d->d1)
7262 {
7263 tx2=tx+bx+d->h-1+box_spacing;
7264
7265 if(has_text)
7266 {
7267 if(d->flags & D_DISABLED)
7268 {
7269 gui_textout_ln(tmp, str, tx2+1, txt_y+1, scheme[jcLIGHT], scheme[jcBOX], 0);
7270 tl=gui_textout_ln(tmp, str, tx2, txt_y, scheme[jcDISABLED_FG], -1, 0);
7271 }
7272 else
7273 {
7274 tl=gui_textout_ln(tmp, str, tx2, txt_y, scheme[jcBOXFG], scheme[jcBOX], 0);
7275 }
7276 }
7277 }
7278
7279 if(d->flags & D_SELECTED)
7280 {
7281 line(tmp, tx+bx+2, ty+2, tx+bx+d->h-3, ty+d->h-3, scheme[jcTEXTFG]);
7282 line(tmp, tx+bx+2, ty+d->h-3, tx+bx+d->h-3, ty+2, scheme[jcTEXTFG]);
7283 }
7284
7285 set_clip_rect(tmp, 0, 0, tmp->w, tmp->h);
7286 if(has_text)
7287 {
7288 dotted_rect(tmp, tx2-1, txt_y-1, tx2+tl, txt_y+fh, (d->flags & D_GOTFOCUS)?scheme[jcDARK]:scheme[jcBOX], scheme[jcBOX]);
7289 }
7290
7291 masked_blit(tmp, screen, 0, 0, d->x-tx, d->y-ty, d->w+tx+tx, d->h+ty+ty);
7292 break;
7293 }
7294 }
7295
7296 int32_t rval = D_O_K;
7297 if(msg != MSG_DRAW)
7298 rval = d_jwinbutton_proc(msg, d, 0);
7299 font = oldfont;
7300 return rval;
7301 }
7302
7303 int32_t jwin_radiofont_proc(int32_t msg, DIALOG *d, int32_t c)
7304 {
7305 FONT *oldfont = font;
7306
7307 if(d->dp2)
7308 {
7309 font = (FONT *)d->dp2;
7310 }
7311
7312 int32_t rval = jwin_radio_proc(msg, d, c);
7313 font = oldfont;
7314 return rval;
7315 }
7316
7317 /* jwin_radio_proc:
7318 * GUI procedure for radio buttons.
7319 * Parameters: d1-button group number; d2-button style (0=circle,1=square);
7320 * dp-text to appear as label to the right of the button.
7321 */
7322 int32_t jwin_radio_proc(int32_t msg, DIALOG *d, int32_t c)
7323 {
7324 int32_t x, center, r, ret, tl=0, tx;
7325 ASSERT(d);
7326
7327 switch(msg)
7328 {
7329 case MSG_DRAW:
7330 // tx=d->x+d->h-1+text_height(font);
7331 tx=d->x+int32_t(text_height(font)*1.5);
7332
7333 if(d->dp)
7334 {
7335 if(d->flags & D_DISABLED)
7336 {
7337 gui_textout_ln(screen, (uint8_t *)d->dp, tx+1, d->y+1+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcLIGHT], scheme[jcBOX], 0);
7338 tl=gui_textout_ln(screen, (uint8_t *)d->dp, tx, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcDISABLED_FG], -1, 0);
7339 }
7340 else
7341 {
7342 tl=gui_textout_ln(screen, (uint8_t *)d->dp, tx, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcBOXFG], scheme[jcBOX], 0);
7343 }
7344 }
7345
7346 x = d->x;
7347 r = d->h/2;
7348
7349 center = x+r;
7350 rectfill(screen, x, d->y, x+d->h-1, d->y+d->h-1, scheme[jcBOX]);
7351
7352 switch(d->d2)
7353 {
7354 case 1:
7355 jwin_draw_frame(screen, x, d->y, d->h, d->h, FR_DEEP);
7356
7357 if(!(d->flags & D_DISABLED))
7358 {
7359 rectfill(screen, x+2, d->y+2, x+d->h-3, d->y+d->h-3, scheme[jcLIGHT]);
7360 }
7361
7362 if(d->flags & D_SELECTED)
7363 {
7364 rectfill(screen, x+r/2, d->y+r/2, x+d->h-1-r/2, d->y+d->h-1-r/2, scheme[jcDARK]);
7365 //line(screen, x+2, d->y+2, x+d->h-3, d->y+d->h-3, scheme[jcDARK]);
7366 //line(screen, x+2, d->y+d->h-3, x+d->h-3, d->y+2, scheme[jcDARK]);
7367 }
7368
7369 break;
7370
7371 default:
7372 circlefill(screen, center, d->y+r, r, scheme[jcTEXTBG]);
7373 arc(screen, center, d->y+r, itofix(32), itofix(160), r, vc(0));
7374 circlefill(screen, center, d->y+r, r-1, scheme[jcTEXTBG]);
7375 arc(screen, center, d->y+r, itofix(32), itofix(160), r-1, vc(0));
7376 circlefill(screen, center, d->y+r, r-2, (d->flags & D_DISABLED)?scheme[jcDISABLED_BG]:scheme[jcTEXTBG]);
7377
7378 if(d->flags & D_SELECTED)
7379 {
7380 circlefill(screen, center, d->y+r, r-3, scheme[jcTEXTFG]);
7381 }
7382
7383 break;
7384 }
7385
7386 if(d->dp)
7387 {
7388 // dotted_rect(screen, tx-1, d->y-1, tx+tl, d->y+d->h-1, (d->flags & D_GOTFOCUS)?scheme[jcDARK]:scheme[jcBOX], scheme[jcBOX]);
7389 dotted_rect(screen, tx-1, d->y-1, tx+tl, d->y+(text_height(font)), (d->flags & D_GOTFOCUS)?scheme[jcDARK]:scheme[jcBOX], scheme[jcBOX]);
7390 d->w=tl+int32_t(text_height(font)*1.5)+1;
7391 }
7392
7393 return D_O_K;
7394
7395 case MSG_KEY:
7396 case MSG_CLICK:
7397 if(d->flags & D_SELECTED)
7398 {
7399 return D_O_K;
7400 }
7401
7402 break;
7403
7404 case MSG_RADIO:
7405 if((c == d->d1) && (d->flags & D_SELECTED))
7406 {
7407 d->flags &= ~D_SELECTED;
7408 object_message(d, MSG_DRAW, 0);
7409 }
7410
7411 break;
7412 }
7413
7414 ret = d_jwinbutton_proc(msg, d, 0);
7415
7416 if(((msg==MSG_KEY) || (msg==MSG_CLICK)) && (d->flags & D_SELECTED) && (!(d->flags & D_EXIT)))
7417 {
7418 d->flags &= ~D_SELECTED;
7419 broadcast_dialog_message(MSG_RADIO, d->d1);
7420 d->flags |= D_SELECTED;
7421 GUI_EVENT(d, geRADIO);
7422 }
7423
7424 return ret;
7425 }
7426
7427
7428 /* 1.5k lookup table for color matching */
7429 uint32_t col_diff[3*128];
7430
7431 /* bestfit_init:
7432 * Color matching is done with weighted squares, which are much faster
7433 * if we pregenerate a little lookup table...
7434 */
7435 71 void bestfit_init(void)
7436 {
7437 int32_t i;
7438
7439 71 col_diff[0] = col_diff[128] = col_diff[256] = 0;
7440
7441
2/2
✓ Branch 0 taken 4473 times.
✓ Branch 1 taken 71 times.
4544 for(i=1; i<64; i++)
7442 {
7443 4473 int32_t k = i * i;
7444 4473 col_diff[0 +i] = col_diff[0 +128-i] = k * (59 * 59);
7445 4473 col_diff[128+i] = col_diff[128+128-i] = k * (30 * 30);
7446 4473 col_diff[256+i] = col_diff[256+128-i] = k * (11 * 11);
7447 4473 }
7448 71 }
7449
7450
7451
7452 /* bestfit_color:
7453 * Searches a palette for the color closest to the requested R, G, B value.
7454 */
7455 int32_t bestfit_color_range(AL_CONST PALETTE pal, int32_t r, int32_t g, int32_t b, uint8_t start, uint8_t end)
7456 {
7457 int32_t i, coldiff, lowest, bestfit;
7458
7459 if(col_diff[1] == 0)
7460 bestfit_init();
7461
7462 bestfit = start;
7463 lowest = INT_MAX;
7464
7465 i = start;
7466
7467 while(i<PAL_SIZE&&i<=end)
7468 {
7469 AL_CONST RGB *rgb = &pal[i];
7470 coldiff = (col_diff + 0) [(rgb->g - g) & 0x7F ];
7471
7472 if(coldiff < lowest)
7473 {
7474 coldiff += (col_diff + 128) [(rgb->r - r) & 0x7F ];
7475
7476 if(coldiff < lowest)
7477 {
7478 coldiff += (col_diff + 256) [(rgb->b - b) & 0x7F ];
7479
7480 if(coldiff < lowest)
7481 {
7482 bestfit = rgb - pal; /* faster than `bestfit = i;' */
7483
7484 if(coldiff == 0)
7485 {
7486 return bestfit;
7487 }
7488
7489 lowest = coldiff;
7490 }
7491 }
7492 }
7493
7494 i++;
7495 }
7496
7497 return bestfit;
7498 }
7499
7500
7501 /* makecol8:
7502 * Converts R, G, and B values (ranging 0-255) to an 8 bit paletted color.
7503 * If the global rgb_map table is initialised, it uses that, otherwise
7504 * it searches through the current palette to find the best match.
7505 */
7506 int32_t makecol8_map(int32_t r, int32_t g, int32_t b, RGB_MAP *table)
7507 {
7508 return table->data[r>>3][g>>3][b>>3];
7509 }
7510
7511
7512 /* create_rgb_table:
7513 * Fills an RGB_MAP lookup table with conversion data for the specified
7514 * palette. This is the faster version by Jan Hubicka.
7515 *
7516 * Uses alg. similar to floodfill - it adds one seed per every color in
7517 * palette to its best position. Then areas around seed are filled by
7518 * same color because it is best approximation for them, and then areas
7519 * about them etc...
7520 *
7521 * It does just about 80000 tests for distances and this is about 100
7522 * times better than normal 256*32000 tests so the calculation time
7523 * is now less than one second at all computers I tested.
7524 */
7525 8193 void create_rgb_table_range(RGB_MAP *table, AL_CONST PALETTE pal_8bit, uint8_t start, uint8_t end, void (*callback)(int32_t pos))
7526 {
7527 #define UNUSED 65535
7528 #define LAST 65532
7529
7530 // Allegro has been modified to use an 8 bit palette, but this method and RGB_MAP still use 6 bit.
7531 PALETTE pal;
7532
2/2
✓ Branch 0 taken 2097408 times.
✓ Branch 1 taken 8193 times.
2105601 for (int i = 0; i < 256; i++)
7533 {
7534 2097408 pal[i] = pal_8bit[i];
7535 2097408 pal[i].r /= 4;
7536 2097408 pal[i].g /= 4;
7537 2097408 pal[i].b /= 4;
7538 2097408 }
7539
7540 /* macro add adds to single linked list */
7541 #define add(i) (next[(i)] == UNUSED ? (next[(i)] = LAST, \
7542 (first != LAST ? (next[last] = (i)) : (first = (i))), \
7543 (last = (i))) : 0)
7544
7545 /* same but w/o checking for first element */
7546 #define add1(i) (next[(i)] == UNUSED ? (next[(i)] = LAST, \
7547 next[last] = (i), \
7548 (last = (i))) : 0)
7549
7550 /* calculates distance between two colors */
7551 #define dist(a1, a2, a3, b1, b2, b3) \
7552 (col_diff[ ((a2) - (b2)) & 0x7F] + \
7553 (col_diff + 128)[((a1) - (b1)) & 0x7F] + \
7554 (col_diff + 256)[((a3) - (b3)) & 0x7F])
7555
7556 /* converts r,g,b to position in array and back */
7557 #define pos(r, g, b) \
7558 (((r) / 2) * 32 * 32 + ((g) / 2) * 32 + ((b) / 2))
7559
7560 #define depos(pal, r, g, b) \
7561 ((b) = ((pal) & 31) * 2, \
7562 (g) = (((pal) >> 5) & 31) * 2, \
7563 (r) = (((pal) >> 10) & 31) * 2)
7564
7565 /* is current color better than pal1? */
7566 #define better(r1, g1, b1, pal1) \
7567 (((int32_t)dist((r1), (g1), (b1), \
7568 (pal1).r, (pal1).g, (pal1).b)) > (int32_t)dist2)
7569
7570 /* checking of position */
7571 #define dopos(rp, gp, bp, ts) \
7572 if ((rp > -1 || r > 0) && (rp < 1 || r < 61) && \
7573 (gp > -1 || g > 0) && (gp < 1 || g < 61) && \
7574 (bp > -1 || b > 0) && (bp < 1 || b < 61)) { \
7575 i = first + rp * 32 * 32 + gp * 32 + bp; \
7576 if (!data[i]) { \
7577 data[i] = val; \
7578 add1(i); \
7579 } \
7580 else if ((ts) && (data[i] != val)) { \
7581 dist2 = (rp ? (col_diff+128)[(r+2*rp-pal[val].r) & 0x7F] : r2) + \
7582 (gp ? (col_diff )[(g+2*gp-pal[val].g) & 0x7F] : g2) + \
7583 (bp ? (col_diff+256)[(b+2*bp-pal[val].b) & 0x7F] : b2); \
7584 if (better((r+2*rp), (g+2*gp), (b+2*bp), pal[data[i]])) { \
7585 data[i] = val; \
7586 add1(i); \
7587 } \
7588 } \
7589 }
7590
7591 int32_t i, curr, r, g, b, val, dist2;
7592 uint32_t r2, g2, b2;
7593 uint16_t next[32*32*32];
7594 uint8_t *data;
7595 8193 int32_t first = LAST;
7596 8193 int32_t last = LAST;
7597 8193 int32_t count = 0;
7598 8193 int32_t cbcount = 0;
7599
7600 #define AVERAGE_COUNT 18000
7601
7602
2/2
✓ Branch 0 taken 8131 times.
✓ Branch 1 taken 62 times.
8193 if(col_diff[1] == 0)
7603 62 bestfit_init();
7604
7605 8193 memset(next, 255, sizeof(next));
7606 8193 memset(table->data, 0, sizeof(char)*32*32*32);
7607
7608 8193 data = (uint8_t *)table->data;
7609
7610 /* add starting seeds for floodfill */
7611
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 270369 times.
✓ Branch 2 taken 262176 times.
✓ Branch 3 taken 8193 times.
270369 for(i=start; i<PAL_SIZE&&i<=end; i++)
7612 {
7613 262176 curr = pos(pal[i].r, pal[i].g, pal[i].b);
7614
7615
2/2
✓ Branch 0 taken 93952 times.
✓ Branch 1 taken 168224 times.
262176 if(next[curr] == UNUSED)
7616 {
7617 168224 data[curr] = i;
7618
3/4
✓ Branch 0 taken 168224 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 160031 times.
✓ Branch 3 taken 8193 times.
168224 add(curr);
7619 168224 }
7620 262176 }
7621
7622 /* main floodfill: two versions of loop for faster growing in blue axis */
7623
2/2
✓ Branch 0 taken 8193 times.
✓ Branch 1 taken 156244017 times.
156252210 while(first < LAST)
7624 {
7625 156244017 depos(first, r, g, b);
7626
7627 /* calculate distance of current color */
7628 156244017 val = data[first];
7629 156244017 r2 = (col_diff+128)[((pal[val].r)-(r)) & 0x7F];
7630 156244017 g2 = (col_diff)[((pal[val].g)-(g)) & 0x7F];
7631 156244017 b2 = (col_diff+256)[((pal[val].b)-(b)) & 0x7F];
7632
7633 /* try to grow to all directions */
7634 #ifdef _MSC_VER
7635 #pragma warning(disable:4127)
7636 #endif
7637
11/12
✓ Branch 0 taken 4209919 times.
✓ Branch 1 taken 152034098 times.
✓ Branch 2 taken 138628870 times.
✓ Branch 3 taken 13405228 times.
✓ Branch 4 taken 13405228 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 127484607 times.
✓ Branch 7 taken 11144263 times.
✓ Branch 8 taken 2996170 times.
✓ Branch 9 taken 8148093 times.
✓ Branch 10 taken 19209 times.
✓ Branch 11 taken 8128884 times.
294872887 dopos(0, 0, 1, 1);
7638
11/12
✓ Branch 0 taken 7155904 times.
✓ Branch 1 taken 149088113 times.
✓ Branch 2 taken 149077865 times.
✓ Branch 3 taken 10248 times.
✓ Branch 4 taken 10248 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 147429336 times.
✓ Branch 7 taken 1648529 times.
✓ Branch 8 taken 695948 times.
✓ Branch 9 taken 952581 times.
✓ Branch 10 taken 940288 times.
✓ Branch 11 taken 12293 times.
305321882 dopos(0, 0,-1, 1);
7639
11/12
✓ Branch 0 taken 4277767 times.
✓ Branch 1 taken 151966250 times.
✓ Branch 2 taken 151090454 times.
✓ Branch 3 taken 875796 times.
✓ Branch 4 taken 875796 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 117777601 times.
✓ Branch 7 taken 33312853 times.
✓ Branch 8 taken 33250885 times.
✓ Branch 9 taken 61968 times.
✓ Branch 10 taken 23552 times.
✓ Branch 11 taken 38416 times.
307334471 dopos(1, 0, 0, 1);
7640
11/12
✓ Branch 0 taken 6558218 times.
✓ Branch 1 taken 149685799 times.
✓ Branch 2 taken 149675042 times.
✓ Branch 3 taken 10757 times.
✓ Branch 4 taken 10757 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 112583968 times.
✓ Branch 7 taken 37091074 times.
✓ Branch 8 taken 30262889 times.
✓ Branch 9 taken 6828185 times.
✓ Branch 10 taken 6396208 times.
✓ Branch 11 taken 431977 times.
305919059 dopos(-1, 0, 0, 1);
7641
11/12
✓ Branch 0 taken 5435342 times.
✓ Branch 1 taken 150808675 times.
✓ Branch 2 taken 129595197 times.
✓ Branch 3 taken 21213478 times.
✓ Branch 4 taken 21213478 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 109488150 times.
✓ Branch 7 taken 20107047 times.
✓ Branch 8 taken 3416418 times.
✓ Branch 9 taken 16690629 times.
✓ Branch 10 taken 14569229 times.
✓ Branch 11 taken 2121400 times.
285839214 dopos(0, 1, 0, 1);
7642
11/12
✓ Branch 0 taken 4179962 times.
✓ Branch 1 taken 152064055 times.
✓ Branch 2 taken 151854857 times.
✓ Branch 3 taken 209198 times.
✓ Branch 4 taken 209198 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 139895210 times.
✓ Branch 7 taken 11959647 times.
✓ Branch 8 taken 11841357 times.
✓ Branch 9 taken 118290 times.
✓ Branch 10 taken 88075 times.
✓ Branch 11 taken 30215 times.
308098874 dopos(0,-1, 0, 1);
7643 #ifdef _MSC_VER
7644 #pragma warning(default:4127)
7645 #endif
7646
7647 /* faster growing of blue direction */
7648
4/4
✓ Branch 0 taken 149088113 times.
✓ Branch 1 taken 7155904 times.
✓ Branch 2 taken 695948 times.
✓ Branch 3 taken 148392165 times.
156244017 if((b > 0) && (data[first-1] == val))
7649 {
7650 148392165 b -= 2;
7651 148392165 first--;
7652 148392165 b2 = (col_diff+256)[((pal[val].b)-(b)) & 0x7F];
7653
7654 #ifdef _MSC_VER
7655 #pragma warning(disable:4127)
7656 #endif
7657
5/6
✓ Branch 0 taken 6158035 times.
✓ Branch 1 taken 142234130 times.
✓ Branch 2 taken 142232849 times.
✓ Branch 3 taken 1281 times.
✓ Branch 4 taken 1281 times.
✗ Branch 5 not taken.
290625014 dopos(-1, 0, 0, 0);
7658
5/6
✓ Branch 0 taken 4148725 times.
✓ Branch 1 taken 144243440 times.
✓ Branch 2 taken 144170688 times.
✓ Branch 3 taken 72752 times.
✓ Branch 4 taken 72752 times.
✗ Branch 5 not taken.
292562853 dopos(1, 0, 0, 0);
7659
5/6
✓ Branch 0 taken 4018152 times.
✓ Branch 1 taken 144374013 times.
✓ Branch 2 taken 144334308 times.
✓ Branch 3 taken 39705 times.
✓ Branch 4 taken 39705 times.
✗ Branch 5 not taken.
292726473 dopos(0,-1, 0, 0);
7660
5/6
✓ Branch 0 taken 5157006 times.
✓ Branch 1 taken 143235159 times.
✓ Branch 2 taken 142760097 times.
✓ Branch 3 taken 475062 times.
✓ Branch 4 taken 475062 times.
✗ Branch 5 not taken.
291152262 dopos(0, 1, 0, 0);
7661 #ifdef _MSC_VER
7662 #pragma warning(default:4127)
7663 #endif
7664
7665 148392165 first++;
7666 148392165 }
7667
7668 /* get next from list */
7669 156244017 i = first;
7670 156244017 first = next[first];
7671 156244017 next[i] = UNUSED;
7672
7673 /* second version of loop */
7674
2/2
✓ Branch 0 taken 6401 times.
✓ Branch 1 taken 156237616 times.
156244017 if(first != LAST)
7675 {
7676 156237616 depos(first, r, g, b);
7677
7678 156237616 val = data[first];
7679 156237616 r2 = (col_diff+128)[((pal[val].r)-(r)) & 0x7F];
7680 156237616 g2 = (col_diff)[((pal[val].g)-(g)) & 0x7F];
7681 156237616 b2 = (col_diff+256)[((pal[val].b)-(b)) & 0x7F];
7682
7683 #ifdef _MSC_VER
7684 #pragma warning(disable:4127)
7685 #endif
7686
11/12
✓ Branch 0 taken 4201476 times.
✓ Branch 1 taken 152036140 times.
✓ Branch 2 taken 135815700 times.
✓ Branch 3 taken 16220440 times.
✓ Branch 4 taken 16220440 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 126421700 times.
✓ Branch 7 taken 9394000 times.
✓ Branch 8 taken 3029458 times.
✓ Branch 9 taken 6364542 times.
✓ Branch 10 taken 17157 times.
✓ Branch 11 taken 6347385 times.
292053316 dopos(0, 0, 1, 1);
7687
11/12
✓ Branch 0 taken 7226297 times.
✓ Branch 1 taken 149011319 times.
✓ Branch 2 taken 149009527 times.
✓ Branch 3 taken 1792 times.
✓ Branch 4 taken 1792 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 147401987 times.
✓ Branch 7 taken 1607540 times.
✓ Branch 8 taken 666245 times.
✓ Branch 9 taken 941295 times.
✓ Branch 10 taken 925413 times.
✓ Branch 11 taken 15882 times.
305247143 dopos(0, 0,-1, 1);
7688
11/12
✓ Branch 0 taken 4111865 times.
✓ Branch 1 taken 152125751 times.
✓ Branch 2 taken 150974247 times.
✓ Branch 3 taken 1151504 times.
✓ Branch 4 taken 1151504 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 117321849 times.
✓ Branch 7 taken 33652398 times.
✓ Branch 8 taken 33599908 times.
✓ Branch 9 taken 52490 times.
✓ Branch 10 taken 21504 times.
✓ Branch 11 taken 30986 times.
307211863 dopos(1, 0, 0, 1);
7689
11/12
✓ Branch 0 taken 6288945 times.
✓ Branch 1 taken 149948671 times.
✓ Branch 2 taken 149941245 times.
✓ Branch 3 taken 7426 times.
✓ Branch 4 taken 7426 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 112698473 times.
✓ Branch 7 taken 37242772 times.
✓ Branch 8 taken 30413108 times.
✓ Branch 9 taken 6829664 times.
✓ Branch 10 taken 6465286 times.
✓ Branch 11 taken 364378 times.
306178861 dopos(-1, 0, 0, 1);
7690
11/12
✓ Branch 0 taken 5556413 times.
✓ Branch 1 taken 150681203 times.
✓ Branch 2 taken 104743863 times.
✓ Branch 3 taken 45937340 times.
✓ Branch 4 taken 45937340 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 85359584 times.
✓ Branch 7 taken 19384279 times.
✓ Branch 8 taken 3471214 times.
✓ Branch 9 taken 15913065 times.
✓ Branch 10 taken 14438667 times.
✓ Branch 11 taken 1474398 times.
260981479 dopos(0, 1, 0, 1);
7691
11/12
✓ Branch 0 taken 4283398 times.
✓ Branch 1 taken 151954218 times.
✓ Branch 2 taken 151705084 times.
✓ Branch 3 taken 249134 times.
✓ Branch 4 taken 249134 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 139834818 times.
✓ Branch 7 taken 11870266 times.
✓ Branch 8 taken 11735324 times.
✓ Branch 9 taken 134942 times.
✓ Branch 10 taken 108821 times.
✓ Branch 11 taken 26121 times.
307942700 dopos(0,-1, 0, 1);
7692 #ifdef _MSC_VER
7693 #pragma warning(default:4127)
7694 #endif
7695
7696
4/4
✓ Branch 0 taken 152036140 times.
✓ Branch 1 taken 4201476 times.
✓ Branch 2 taken 3029458 times.
✓ Branch 3 taken 149006682 times.
156237616 if((b < 61) && (data[first + 1] == val))
7697 {
7698 149006682 b += 2;
7699 149006682 first++;
7700 149006682 b2 = (col_diff+256)[((pal[val].b)-(b)) & 0x7f];
7701
7702 #ifdef _MSC_VER
7703 #pragma warning(disable:4127)
7704 #endif
7705
5/6
✓ Branch 0 taken 5963529 times.
✓ Branch 1 taken 143043153 times.
✓ Branch 2 taken 134561878 times.
✓ Branch 3 taken 8481275 times.
✓ Branch 4 taken 8481275 times.
✗ Branch 5 not taken.
283568560 dopos(-1, 0, 0, 0);
7706
5/6
✓ Branch 0 taken 3991529 times.
✓ Branch 1 taken 145015153 times.
✓ Branch 2 taken 99905321 times.
✓ Branch 3 taken 45109832 times.
✓ Branch 4 taken 45109832 times.
✗ Branch 5 not taken.
248912003 dopos(1, 0, 0, 0);
7707
5/6
✓ Branch 0 taken 4145912 times.
✓ Branch 1 taken 144860770 times.
✓ Branch 2 taken 141220031 times.
✓ Branch 3 taken 3640739 times.
✓ Branch 4 taken 3640739 times.
✗ Branch 5 not taken.
290226713 dopos(0,-1, 0, 0);
7708
5/6
✓ Branch 0 taken 5274234 times.
✓ Branch 1 taken 143732448 times.
✓ Branch 2 taken 32545435 times.
✓ Branch 3 taken 111187013 times.
✓ Branch 4 taken 111187013 times.
✗ Branch 5 not taken.
181552117 dopos(0, 1, 0, 0);
7709 #ifdef _MSC_VER
7710 #pragma warning(default:4127)
7711 #endif
7712
7713 149006682 first--;
7714 149006682 }
7715
7716 156237616 i = first;
7717 156237616 first = next[first];
7718 156237616 next[i] = UNUSED;
7719 156237616 }
7720
7721 156244017 count++;
7722
7723
2/2
✓ Branch 0 taken 154139440 times.
✓ Branch 1 taken 2104577 times.
156244017 if(count == (cbcount+1)*AVERAGE_COUNT/256)
7724 {
7725
2/2
✓ Branch 0 taken 7169 times.
✓ Branch 1 taken 2097408 times.
2104577 if(cbcount < 256)
7726 {
7727
1/2
✓ Branch 0 taken 2097408 times.
✗ Branch 1 not taken.
2097408 if(callback)
7728 callback(cbcount);
7729
7730 2097408 cbcount++;
7731 2097408 }
7732 2104577 }
7733 }
7734
7735
1/2
✓ Branch 0 taken 8193 times.
✗ Branch 1 not taken.
8193 if(callback)
7736 while(cbcount < 256)
7737 callback(cbcount++);
7738 8193 }
7739
7740 int32_t short_bmp_avg(BITMAP *bmp, int32_t i)
7741 {
7742 int32_t j=((int16_t *)bmp->line[0])[i];
7743 int32_t r=getr15(j);
7744 int32_t g=getg15(j);
7745 int32_t b=getb15(j);
7746 int32_t k=1;
7747
7748 if(i>0)
7749 {
7750 j=((int16_t *)bmp->line[0])[i-1];
7751 r+=getr15(j);
7752 g+=getg15(j);
7753 b+=getb15(j);
7754 ++k;
7755 }
7756
7757 if(i<(bmp->w-2))
7758 {
7759 j=((int16_t *)bmp->line[0])[i+1];
7760 r+=getr15(j);
7761 g+=getg15(j);
7762 b+=getb15(j);
7763 ++k;
7764 }
7765
7766 r/=k;
7767 g/=k;
7768 b/=k;
7769 return makecol15(r, g, b);
7770 }
7771
7772 // A consistent RENG (random enough number generator) for dither_rect()
7773 static uint16_t lfsr;
7774
7775 void lfsrInit()
7776 {
7777 lfsr=1;
7778 }
7779
7780 uint16_t lfsrNext()
7781 {
7782 auto bits=(lfsr^(lfsr>>2)^(lfsr>>3)^(lfsr>>5))&1;
7783 lfsr=(lfsr>>1)|(bits<<15);
7784 return lfsr;
7785 }
7786
7787 void dither_rect(BITMAP *bmp, PALETTE *pal, int32_t x1, int32_t y1, int32_t x2, int32_t y2,
7788 int32_t src_color1, int32_t src_color2, uint8_t dest_color1,
7789 uint8_t dest_color2)
7790 {
7791 BITMAP *src_bmp=create_bitmap_ex(15, abs(x2-x1)+1, 1);
7792 BITMAP *dest_bmp=create_bitmap_ex(8, abs(x2-x1)+1, abs(y2-y1)+1);
7793 int32_t r, g, b, direction=1;
7794 int32_t c;
7795 int32_t r1, r2, g1, g2, b1, b2;
7796 int32_t (*diff[2])[3];
7797 diff[0] = new int32_t[x2-x1+3][3];
7798 diff[1] = new int32_t[x2-x1+3][3];
7799 int32_t cdiff[3];
7800 RGB_MAP table;
7801 int32_t temp;
7802 int32_t red_rand_strength=0, green_rand_strength=0, blue_rand_strength=0;
7803
7804 lfsrInit();
7805 clear_bitmap(dest_bmp);
7806
7807 if(x1>x2)
7808 {
7809 temp=x1;
7810 x1=x2;
7811 x2=temp;
7812 }
7813
7814 if(y1>y2)
7815 {
7816 temp=y1;
7817 y1=y2;
7818 y2=temp;
7819 }
7820
7821 if(src_color1>src_color2)
7822 {
7823 temp=src_color1;
7824 src_color1=src_color2;
7825 src_color2=temp;
7826 }
7827
7828 if(dest_color1>dest_color2)
7829 {
7830 temp=dest_color1;
7831 dest_color1=dest_color2;
7832 dest_color2=temp;
7833 }
7834
7835 create_rgb_table_range(&table, *pal, dest_color1, dest_color2, NULL);
7836 r1=getr15(src_color1);
7837 r2=getr15(src_color2);
7838 g1=getg15(src_color1);
7839 g2=getg15(src_color2);
7840 b1=getb15(src_color1);
7841 b2=getb15(src_color2);
7842 red_rand_strength=getr8(dest_color1+1)-getr8(dest_color1);
7843 green_rand_strength=getg8(dest_color1+1)-getg8(dest_color1);
7844 blue_rand_strength=getb8(dest_color1+1)-getb8(dest_color1);
7845 memset(cdiff,0,3*sizeof(float));
7846 memset(diff[0],0,(x2-x1+3)*3*sizeof(int32_t));
7847 memset(diff[1],0,(x2-x1+3)*3*sizeof(int32_t));
7848 int32_t mc, mr, mg, mb;
7849
7850 for(int32_t i=0; i<src_bmp->w; i++)
7851 {
7852 r = mix_value(r1, r2, i, src_bmp->w-1);
7853 g = mix_value(g1, g2, i, src_bmp->w-1);
7854 b = mix_value(b1, b2, i, src_bmp->w-1);
7855 c = makecol15(r,g,b);
7856 ((int16_t *)src_bmp->line[0])[i] = c;
7857 }
7858
7859 uint8_t tempcolor, origcolor;
7860
7861 for(int32_t j=0; j<=y2-y1; ++j)
7862 {
7863 if(direction==1)
7864 {
7865 for(int32_t i=0; i<=x2-x1; ++i)
7866 {
7867 mc=((int16_t *)src_bmp->line[0])[i];
7868 mr=bound(getr15(mc)+lfsrNext()%(red_rand_strength*2+1)-(red_rand_strength*1),0,255);
7869 mg=bound(getg15(mc)+lfsrNext()%(green_rand_strength*2+1)-(green_rand_strength*1),0,255);
7870 mb=bound(getb15(mc)+lfsrNext()%(blue_rand_strength*2+1)-(blue_rand_strength*1),0,255);
7871 cdiff[0]=bound(mr+
7872 diff[0][i][0]+
7873 diff[0][i+1][0]+
7874 diff[0][i+2][0]+
7875 cdiff[0],0,255);
7876 cdiff[1]=bound(mg+
7877 diff[0][i][1]+
7878 diff[0][i+1][1]+
7879 diff[0][i+2][1]+
7880 cdiff[1],0,255);
7881 cdiff[2]=bound(mb+
7882 diff[0][i][2]+
7883 diff[0][i+1][2]+
7884 diff[0][i+2][2]+
7885 cdiff[2],0,255);
7886 // bmp->line[j][i+x1]=bound(makecol8_map(int32_t(cdiff[0]),int32_t(cdiff[1]),int32_t(cdiff[2]),&table),dest_color1,dest_color2);
7887 origcolor=makecol8_map(mr,mg,mb,&table);
7888 // tempcolor=bound(makecol8_map(cdiff[0],cdiff[1],cdiff[2],&table),origcolor-1,origcolor+1);
7889 tempcolor=makecol8_map(cdiff[0],cdiff[1],cdiff[2],&table);
7890 dest_bmp->line[j][i]=tempcolor;
7891 r=getr8(tempcolor);
7892 g=getg8(tempcolor);
7893 b=getb8(tempcolor);
7894 diff[1][i][0]=(cdiff[0]-r)*3/16;
7895 diff[1][i][1]=(cdiff[1]-g)*3/16;
7896 diff[1][i][2]=(cdiff[2]-b)*3/16;
7897 diff[1][i+1][0]=(cdiff[0]-r)*5/16;
7898 diff[1][i+1][1]=(cdiff[1]-g)*5/16;
7899 diff[1][i+1][2]=(cdiff[2]-b)*5/16;
7900 diff[1][i+2][0]=(cdiff[0]-r)*1/16;
7901 diff[1][i+2][1]=(cdiff[1]-g)*1/16;
7902 diff[1][i+2][2]=(cdiff[2]-b)*1/16;
7903 cdiff[0]=(cdiff[0]-r)*7/16;
7904 cdiff[1]=(cdiff[1]-g)*7/16;
7905 cdiff[2]=(cdiff[2]-b)*7/16;
7906 }
7907
7908 memcpy(diff[0],diff[1],(x2-x1+3)*3*sizeof(int32_t));
7909 memset(diff[1],0,(x2-x1+3)*3*sizeof(int32_t));
7910 direction=-1;
7911 }
7912 else
7913 {
7914 for(int32_t i=x2-x1; i>=0; --i)
7915 {
7916 mc=((int16_t *)src_bmp->line[0])[i];
7917 mr=getr15(mc);
7918 mg=getg15(mc);
7919 mb=getb15(mc);
7920 cdiff[0]=bound(mr+
7921 diff[0][i][0]+
7922 diff[0][i+1][0]+
7923 diff[0][i+2][0]+
7924 cdiff[0],0,255);
7925 cdiff[1]=bound(mg+
7926 diff[0][i][1]+
7927 diff[0][i+1][1]+
7928 diff[0][i+2][1]+
7929 cdiff[1],0,255);
7930 cdiff[2]=bound(mb+
7931 diff[0][i][2]+
7932 diff[0][i+1][2]+
7933 diff[0][i+2][2]+
7934 cdiff[2],0,255);
7935 // bmp->line[j][i+x1]=bound(makecol8_map(int32_t(cdiff[0]),int32_t(cdiff[1]),int32_t(cdiff[2]),&table),dest_color1,dest_color2);
7936 origcolor=makecol8_map(mr,mg,mb,&table);
7937 // tempcolor=bound(makecol8_map(cdiff[0],cdiff[1],cdiff[2],&table),origcolor-1,origcolor+1);
7938 tempcolor=makecol8_map(cdiff[0],cdiff[1],cdiff[2],&table);
7939 dest_bmp->line[j][i]=tempcolor;
7940 r=getr8(tempcolor);
7941 g=getg8(tempcolor);
7942 b=getb8(tempcolor);
7943 diff[1][i][0]=(cdiff[0]-r)*3/16;
7944 diff[1][i][1]=(cdiff[1]-g)*3/16;
7945 diff[1][i][2]=(cdiff[2]-b)*3/16;
7946 diff[1][i+1][0]=(cdiff[0]-r)*5/16;
7947 diff[1][i+1][1]=(cdiff[1]-g)*5/16;
7948 diff[1][i+1][2]=(cdiff[2]-b)*5/16;
7949 diff[1][i+2][0]=(cdiff[0]-r)*1/16;
7950 diff[1][i+2][1]=(cdiff[1]-g)*1/16;
7951 diff[1][i+2][2]=(cdiff[2]-b)*1/16;
7952 cdiff[0]=(cdiff[0]-r)*7/16;
7953 cdiff[1]=(cdiff[1]-g)*7/16;
7954 cdiff[2]=(cdiff[2]-b)*7/16;
7955 }
7956
7957 memcpy(diff[0],diff[1],(x2-x1+3)*3*sizeof(float));
7958 memset(diff[1],0,(x2-x1+3)*3*sizeof(float));
7959 direction=1;
7960 }
7961 }
7962
7963 blit(dest_bmp, bmp, 0, 0, x1, y1, x2-x1+1, y2-y1+1);
7964 delete[] diff[1];
7965 delete[] diff[0];
7966 destroy_bitmap(src_bmp);
7967 destroy_bitmap(dest_bmp);
7968 return;
7969 }
7970
7971 bool do_text_button(int32_t x,int32_t y,int32_t w,int32_t h,const char *text)
7972 {
7973 bool over=false;
7974
7975 while(gui_mouse_b())
7976 {
7977 if(mouse_in_rect(x,y,w,h))
7978 {
7979 if(!over)
7980 {
7981 vsync();
7982 jwin_draw_text_button(screen, x, y, w, h, text, D_SELECTED, true);
7983 over=true;
7984 update_hw_screen();
7985 }
7986 }
7987 else
7988 {
7989 if(over)
7990 {
7991 vsync();
7992 jwin_draw_text_button(screen, x, y, w, h, text, 0, true);
7993 over=false;
7994 update_hw_screen();
7995 }
7996 }
7997 rest(1);
7998 }
7999
8000 return over;
8001 }
8002
8003 bool do_text_button_reset(int32_t x,int32_t y,int32_t w,int32_t h,const char *text)
8004 {
8005 bool over=false;
8006
8007 while(gui_mouse_b())
8008 {
8009 //vsync();
8010 if(mouse_in_rect(x,y,w,h))
8011 {
8012 if(!over)
8013 {
8014 vsync();
8015 jwin_draw_text_button(screen, x, y, w, h, text, D_SELECTED, true);
8016 over=true;
8017
8018 update_hw_screen();
8019 }
8020 }
8021 else
8022 {
8023 if(over)
8024 {
8025 vsync();
8026 jwin_draw_text_button(screen, x, y, w, h, text, 0, true);
8027 over=false;
8028
8029 update_hw_screen();
8030 }
8031 }
8032 rest(1);
8033 }
8034
8035 if(over)
8036 {
8037 vsync();
8038 jwin_draw_text_button(screen, x, y, w, h, text, 0, true);
8039
8040 update_hw_screen();
8041 }
8042
8043 return over;
8044 }
8045 bool do_icon_button_reset(int32_t x,int32_t y,int32_t w,int32_t h,int icon)
8046 {
8047 bool over=false;
8048
8049 while(gui_mouse_b())
8050 {
8051 //vsync();
8052 if(mouse_in_rect(x,y,w,h))
8053 {
8054 if(!over)
8055 {
8056 vsync();
8057 jwin_draw_icon_button(screen, x, y, w, h, icon, D_SELECTED, true);
8058 over=true;
8059
8060 update_hw_screen();
8061 }
8062 }
8063 else
8064 {
8065 if(over)
8066 {
8067 vsync();
8068 jwin_draw_icon_button(screen, x, y, w, h, icon, 0, true);
8069 over=false;
8070
8071 update_hw_screen();
8072 }
8073 }
8074 rest(1);
8075 }
8076
8077 if(over)
8078 {
8079 vsync();
8080 jwin_draw_icon_button(screen, x, y, w, h, icon, 0, true);
8081
8082 update_hw_screen();
8083 }
8084
8085 return over;
8086 }
8087
8088 int32_t jwin_tab_proc(int32_t msg, DIALOG *d, int32_t c)
8089 {
8090 int32_t i;
8091 int32_t tx;
8092 int32_t sd=2; //selected delta
8093 TABPANEL *panel=(TABPANEL *)d->dp;
8094 DIALOG *panel_dialog=NULL, *current_object=NULL;
8095 int32_t selected=0;
8096 int32_t counter=0;
8097 ASSERT(d);
8098 int32_t temp_d, temp_d2;
8099
8100 if(d->dp==NULL) return D_O_K;
8101
8102 panel_dialog=(DIALOG *)d->dp3;
8103
8104 if (msg != MSG_START && msg != MSG_END)
8105 {
8106 bool redraw = false;
8107 for (i = 0; panel[i].text; ++i)
8108 {
8109 if ((panel[i].flags & D_SELECTED) && !(d->flags & D_HIDDEN))
8110 {
8111 for (counter = 0; counter < panel[i].objects; counter++)
8112 {
8113 current_object = panel_dialog + (panel[i].dialog[counter]);
8114 current_object->flags &= ~D_HIDDEN;
8115 if (object_message(current_object, MSG_IDLE, 0) & D_REDRAW)
8116 redraw = true;
8117 }
8118 }
8119 else
8120 {
8121 for (counter = 0; counter < panel[i].objects; counter++)
8122 {
8123 current_object = panel_dialog + (panel[i].dialog[counter]);
8124 current_object->flags |= D_HIDDEN;
8125 if (object_message(current_object, MSG_IDLE, 0) & D_REDRAW)
8126 redraw = true;
8127 }
8128 }
8129
8130 /*if (d->flags & D_HIDDEN)
8131 {
8132 for(counter=0; counter<panel[i].objects; counter++)
8133 {
8134 current_object=panel_dialog+(panel[i].dialog[counter]);
8135 current_object->x=zq_screen_w*3;
8136 current_object->y=zq_screen_h*3;
8137 }
8138 }*/
8139 }
8140 if (redraw)
8141 broadcast_dialog_message(MSG_DRAW, 0);
8142 }
8143 FONT *oldfont = font;
8144 switch(msg)
8145 {
8146 case MSG_DRAW:
8147 {
8148 if(d->x<zq_screen_w&&d->y<zq_screen_h)
8149 {
8150 if(d->dp2)
8151 {
8152 font = (FONT *)d->dp2;
8153 }
8154
8155 panel_dialog=(DIALOG *)d->dp3;
8156 rectfill(screen, d->x, d->y, d->x+d->w-1, d->y+8+text_height(font), scheme[jcBOX]); //tab area
8157 rectfill(screen, d->x+1, d->y+sd+text_height(font)+7, d->x+d->w-2, d->y+sd+d->h-2, scheme[jcBOX]); //panel
8158 vline(screen, d->x, d->y+sd+7+text_height(font), d->y+sd+d->h-2, scheme[jcLIGHT]);
8159 vline(screen, d->x+1, d->y+sd+7+text_height(font), d->y+sd+d->h-3, scheme[jcMEDLT]);
8160 vline(screen, d->x+d->w-2, d->y+sd+7+text_height(font), d->y+sd+d->h-2, scheme[jcMEDDARK]);
8161 vline(screen, d->x+d->w-1, d->y+sd+7+text_height(font)-1, d->y+sd+d->h-1, scheme[jcDARK]);
8162 hline(screen, d->x+1, d->y+sd+d->h-2, d->x+d->w-3, scheme[jcMEDDARK]);
8163 hline(screen, d->x, d->y+sd+d->h-1, d->x+d->w-2, scheme[jcDARK]);
8164 tx=d->x;
8165
8166 if(d->dp)
8167 {
8168 if(!(panel[((d->d1&0xFF00)>>8)].flags&D_SELECTED))
8169 {
8170 hline(screen, tx+1, d->y+sd+6+text_height(font)+1, tx+2, scheme[jcMEDLT]); //initial bottom
8171 hline(screen, tx, d->y+sd+6+text_height(font), tx+1, scheme[jcLIGHT]); //initial bottom
8172 }
8173
8174 tx+=2;
8175
8176 for(i=0; panel[i].text; ++i)
8177 {
8178 if(panel[i].flags&D_SELECTED)
8179 {
8180 selected=i;
8181 }
8182 }
8183
8184 for(i=((d->d1&0xFF00)>>8); panel[i].text&&i<=last_visible_tab(panel,((d->d1&0xFF00)>>8),d->w); ++i)
8185 {
8186 sd=(panel[i].flags&D_SELECTED)?0:2;
8187
8188 if((i==((d->d1&0xFF00)>>8)) || (!(panel[i-1].flags&D_SELECTED)))
8189 {
8190 vline(screen, tx-(2-sd), d->y+sd+2, d->y+8+text_height(font), scheme[jcLIGHT]); //left side
8191 vline(screen, tx-(2-sd)+1, d->y+sd+2, d->y+8+text_height(font), scheme[jcMEDLT]); //left side
8192 putpixel(screen, tx+1-(2-sd), d->y+sd+1, scheme[jcLIGHT]); //left angle
8193 }
8194
8195 hline(screen, tx+2-(2-sd), d->y+sd, tx+12+(2-sd)+text_length(font, (char *)panel[i].text), scheme[jcLIGHT]); //top
8196 hline(screen, tx+2-(2-sd), d->y+sd+1, tx+12+(2-sd)+text_length(font, (char *)panel[i].text), scheme[jcMEDLT]); //top
8197
8198 if(!(panel[i].flags&D_SELECTED))
8199 {
8200 hline(screen, tx+1, d->y+sd+6+text_height(font), tx+13+text_length(font, (char *)panel[i].text)+1, scheme[jcLIGHT]); //bottom
8201 hline(screen, tx, d->y+sd+6+text_height(font)+1, tx+13+text_length(font, (char *)panel[i].text)+1, scheme[jcMEDLT]); //bottom
8202 }
8203
8204 tx+=4;
8205 gui_textout_ln(screen, (uint8_t*)panel[i].text, tx+4, d->y+sd+4, scheme[jcBOXFG], scheme[jcBOX], 0);
8206 tx+=text_length(font, (char *)panel[i].text)+10;
8207
8208 if(!(panel[i+1].text) || (!(panel[i+1].flags&D_SELECTED)))
8209 {
8210 putpixel(screen, tx-1+(2-sd), d->y+sd+1, scheme[jcDARK]); //right angle
8211 vline(screen, tx+(2-sd), d->y+sd+2, d->y+8+text_height(font)-1, scheme[jcDARK]); //right side
8212 vline(screen, tx+(2-sd)-1, d->y+sd+2, d->y+8+text_height(font)-(sd?1:0), scheme[jcMEDDARK]); //right side
8213 }
8214
8215 tx++;
8216 }
8217
8218 if(((d->d1&0xFF00)>>8)!=0||last_visible_tab(panel,((d->d1&0xFF00)>>8),d->w)+1<tab_count(panel))
8219 {
8220 jwin_draw_icon_button(screen,d->x+d->w-14,d->y+2, 14, 14, BTNICON_ARROW_RIGHT, 0, true);
8221 jwin_draw_icon_button(screen,d->x+d->w-28,d->y+2, 14, 14, BTNICON_ARROW_LEFT, 0, true);
8222 }
8223 }
8224
8225 if((tx+(2-sd))<(d->x+d->w))
8226 {
8227 hline(screen, tx+(2-sd)-1, d->y+8+text_height(font), d->x+d->w-1, scheme[jcLIGHT]); //ending bottom
8228 hline(screen, tx+(2-sd)-2, d->y+8+text_height(font)+1, d->x+d->w-2, scheme[jcMEDLT]); //ending bottom
8229 }
8230
8231 font = oldfont;
8232
8233 //what dialog is this tab control in (programmer must set manually)
8234 panel_dialog=(DIALOG *)d->dp3;
8235
8236 //for each object handled by the currently selected tab...
8237 for(counter=0; counter<panel[selected].objects; counter++)
8238 {
8239 //assign current_object to one of the controls handled by the tab
8240 current_object=panel_dialog+(panel[selected].dialog[counter]);
8241 //remember the x and y positions of the control
8242 current_object->x=panel[selected].xy[counter*2];
8243 current_object->y=panel[selected].xy[counter*2+1];
8244 object_message(current_object, MSG_DRAW, 0);
8245 }
8246
8247 //if there was a previously selected tab...
8248 if((d->d1&0x00FF)!=0x00FF)
8249 {
8250 //for each object handled by the tab
8251 for(counter=0; counter<panel[d->d1&0xFF].objects; counter++)
8252 {
8253 //assign current_object to one of the controls handled by the tab
8254 current_object=panel_dialog+(panel[d->d1&0xFF].dialog[counter]);
8255 // //remember the x and y positions of the control
8256 // panel[d->d1].xy[counter*2]=current_object->x;
8257 // panel[d->d1].xy[counter*2+1]=current_object->y;
8258 current_object->x=zq_screen_w*3;
8259 current_object->y=zq_screen_h*3;
8260 }
8261 }
8262 }
8263 }
8264 break;
8265
8266 case MSG_CLICK:
8267 {
8268 d->d1&=0xFF00;
8269 d->d1|=0x00FF;
8270 if(d->dp2)
8271 {
8272 font = (FONT *)d->dp2;
8273 }
8274
8275 // is the mouse on one of the tab arrows (if visible) or in the tab area?
8276 if(uses_tab_arrows(panel, d->w)&&(mouse_in_rect(d->x+d->w-28, d->y+2, 28, 14)))
8277 {
8278 if(mouse_in_rect(d->x+d->w-28, d->y+2, 14, 14))
8279 {
8280 if(do_icon_button_reset(d->x+d->w-28, d->y+2, 14, 14, BTNICON_ARROW_LEFT))
8281 {
8282 temp_d=((d->d1&0xFF00)>>8);
8283 temp_d2=(d->d1&0x00FF);
8284
8285 if(temp_d>0)
8286 {
8287 --temp_d;
8288 }
8289
8290 d->d1=(temp_d<<8)|temp_d2;
8291 d->flags|=D_DIRTY;
8292 }
8293 }
8294 else if(mouse_in_rect(d->x+d->w-14, d->y+2, 14, 14))
8295 {
8296 if(do_icon_button_reset(d->x+d->w-14, d->y+2, 14, 14, BTNICON_ARROW_RIGHT))
8297 {
8298 temp_d=((d->d1&0xFF00)>>8);
8299 temp_d2=(d->d1&0x00FF);
8300
8301 if(last_visible_tab(panel, temp_d, d->w)<(tab_count(panel)-1))
8302 {
8303 ++temp_d;
8304 }
8305
8306 d->d1=(temp_d<<8)|temp_d2;
8307 d->flags|=D_DIRTY;
8308 }
8309 }
8310 }
8311 else
8312 {
8313 d_tab_proc(msg, d, c);
8314 }
8315 font = oldfont;
8316 jwin_tab_proc(MSG_IDLE,d,0);
8317 }
8318 break;
8319
8320 default:
8321 return d_tab_proc(msg, d, c);
8322 break;
8323 }
8324
8325 panel_dialog=(DIALOG *)d->dp3;
8326
8327 if(d->flags & D_HIDDEN)
8328 {
8329 for(i=0; panel[i].text; ++i)
8330 {
8331 for(counter=0; counter<panel[i].objects; counter++)
8332 {
8333 current_object=panel_dialog+(panel[i].dialog[counter]);
8334 current_object->x=zq_screen_w*3;
8335 current_object->y=zq_screen_h*3;
8336 }
8337 }
8338
8339 //d->x=zq_screen_w*3;
8340 //d->y=zq_screen_h*3;
8341 }
8342 else
8343 {
8344 for(i=0; panel[i].text; ++i)
8345 {
8346 for(counter=0; counter<panel[i].objects; counter++)
8347 {
8348 current_object=panel_dialog+(panel[i].dialog[counter]);
8349 current_object->x=panel[i].xy[counter*2];
8350 current_object->y=panel[i].xy[counter*2+1];
8351 }
8352 }
8353
8354 // d->x=zq_screen_w*3;
8355 //d->y=zq_screen_h*3;
8356 }
8357
8358 return broadcast_dialog_message(MSG_IDLE, 0);
8359
8360 // return D_O_K;
8361 }
8362
8363 int32_t discern_tab(GUI::TabPanel *panel, int32_t first_tab, int32_t x)
8364 {
8365 int32_t w=0;
8366
8367 for(size_t i=first_tab; i < panel->getSize(); i++)
8368 {
8369 w+=text_length(font, panel->getName(i))+15;
8370
8371 if(w>x)
8372 {
8373 return i;
8374 }
8375 }
8376
8377 return -1;
8378 }
8379 int32_t tabs_width(GUI::TabPanel *panel)
8380 {
8381 int32_t w=0;
8382
8383 for(size_t i=0; i < panel->getSize(); ++i)
8384 {
8385 w+=text_length(font, panel->getName(i))+15;
8386 }
8387
8388 return w+1;
8389 }
8390 bool uses_tab_arrows(GUI::TabPanel *panel, int32_t maxwidth)
8391 {
8392 return (tabs_width(panel)>maxwidth);
8393 }
8394 size_t last_visible_tab(GUI::TabPanel *panel, int32_t first_tab, int32_t maxwidth)
8395 {
8396 size_t i;
8397 int32_t w=0;
8398
8399 if(uses_tab_arrows(panel, maxwidth))
8400 {
8401 maxwidth-=28;
8402 }
8403
8404 for(i=first_tab; i < panel->getSize(); ++i)
8405 {
8406 w+=text_length(font, panel->getName(i))+15;
8407
8408 if(w>maxwidth)
8409 {
8410 return i-1;
8411 }
8412 }
8413
8414 return i-1;
8415 }
8416 int32_t displayed_tabs_width(GUI::TabPanel *panel, int32_t first_tab, int32_t maxwidth)
8417 {
8418 size_t i=0;
8419 int32_t w=0;
8420
8421 for(i=first_tab; i<=last_visible_tab(panel, first_tab, maxwidth); ++i)
8422 {
8423 w+=text_length(font, panel->getName(i))+15;
8424 }
8425
8426 return w+1;
8427 }
8428
8429 INLINE int32_t is_in_rect(int32_t x,int32_t y,int32_t rx1,int32_t ry1,int32_t rx2,int32_t ry2)
8430 {
8431 return x>=rx1 && x<=rx2 && y>=ry1 && y<=ry2;
8432 }
8433
8434 int32_t new_tab_proc(int32_t msg, DIALOG *d, int32_t c)
8435 {
8436 assert(d->flags&D_NEW_GUI);
8437
8438 int32_t tx;
8439 int32_t ret = D_O_K;
8440 int32_t sd=2; //selected delta
8441 static bool skipredraw = false;
8442 GUI::TabPanel *panel=(GUI::TabPanel*)d->dp;
8443 ASSERT(d);
8444
8445 if(d->dp==NULL) return D_O_K;
8446
8447 FONT *oldfont = font;
8448 if(d->dp2)
8449 {
8450 font = (FONT *)d->dp2;
8451 }
8452
8453 switch(msg)
8454 {
8455 case MSG_DRAW:
8456 {
8457 if(skipredraw)
8458 {
8459 skipredraw = false;
8460 ret = D_REDRAW;
8461 break;
8462 }
8463 if(d->x<zq_screen_w&&d->y<zq_screen_h)
8464 {
8465 rectfill(screen, d->x, d->y, d->x+d->w-1, d->y+8+text_height(font), scheme[jcBOX]); //tab area
8466 rectfill(screen, d->x+1, d->y+sd+text_height(font)+7, d->x+d->w-2, d->y+sd+d->h-2, scheme[jcBOX]); //panel
8467 vline(screen, d->x, d->y+sd+7+text_height(font), d->y+sd+d->h-2, scheme[jcLIGHT]);
8468 vline(screen, d->x+1, d->y+sd+7+text_height(font), d->y+sd+d->h-3, scheme[jcMEDLT]);
8469 vline(screen, d->x+d->w-2, d->y+sd+7+text_height(font), d->y+sd+d->h-2, scheme[jcMEDDARK]);
8470 vline(screen, d->x+d->w-1, d->y+sd+7+text_height(font)-1, d->y+sd+d->h-1, scheme[jcDARK]);
8471 hline(screen, d->x+1, d->y+sd+d->h-2, d->x+d->w-3, scheme[jcMEDDARK]);
8472 hline(screen, d->x, d->y+sd+d->h-1, d->x+d->w-2, scheme[jcDARK]);
8473 tx=d->x;
8474
8475 if(d->dp)
8476 {
8477 if(panel->getCurrentIndex() != d->d1)
8478 {
8479 hline(screen, tx+1, d->y+sd+6+text_height(font)+1, tx+2, scheme[jcMEDLT]); //initial bottom
8480 hline(screen, tx, d->y+sd+6+text_height(font), tx+1, scheme[jcLIGHT]); //initial bottom
8481 }
8482
8483 tx+=2;
8484
8485 for(size_t i=d->d1; i < panel->getSize()&&i<=last_visible_tab(panel,d->d1,d->w); ++i)
8486 {
8487 sd=(i==panel->getCurrentIndex())?0:2;
8488
8489 if((i==d->d1) || (i-1 != panel->getCurrentIndex()))
8490 {
8491 vline(screen, tx-(2-sd), d->y+sd+2, d->y+8+text_height(font), scheme[jcLIGHT]); //left side
8492 vline(screen, tx-(2-sd)+1, d->y+sd+2, d->y+8+text_height(font), scheme[jcMEDLT]); //left side
8493 putpixel(screen, tx+1-(2-sd), d->y+sd+1, scheme[jcLIGHT]); //left angle
8494 }
8495
8496 hline(screen, tx+2-(2-sd), d->y+sd, tx+12+(2-sd)+text_length(font, panel->getName(i)), scheme[jcLIGHT]); //top
8497 hline(screen, tx+2-(2-sd), d->y+sd+1, tx+12+(2-sd)+text_length(font, panel->getName(i)), scheme[jcMEDLT]); //top
8498
8499 if(i!=panel->getCurrentIndex())
8500 {
8501 hline(screen, tx+1, d->y+sd+6+text_height(font), tx+13+text_length(font, panel->getName(i))+1, scheme[jcLIGHT]); //bottom
8502 hline(screen, tx, d->y+sd+6+text_height(font)+1, tx+13+text_length(font, panel->getName(i))+1, scheme[jcMEDLT]); //bottom
8503 }
8504 else if(d->flags & D_GOTFOCUS)
8505 {
8506 hline(screen, tx+1, d->y+sd+6+text_height(font), tx+13+text_length(font, panel->getName(i))+1, scheme[jcBOXFG]); //bottom
8507 hline(screen, tx, d->y+sd+6+text_height(font)+1, tx+13+text_length(font, panel->getName(i))+1, scheme[jcBOXFG]); //bottom
8508 }
8509
8510 tx+=4;
8511 uint8_t* pname = (uint8_t*)(panel->getName(i));
8512 bool dis = panel->getDisabled(i);
8513 if(dis)
8514 gui_textout_ln(screen, pname, tx+5, d->y+sd+5, scheme[jcLIGHT], scheme[jcBOX], 0);
8515 gui_textout_ln(screen, pname, tx+4, d->y+sd+4, scheme[dis ? jcDISABLED_FG : jcBOXFG], dis ? -1 : scheme[jcBOX], 0);
8516 tx+=text_length(font, (const char*)pname)+10;
8517
8518 if((i+1>=panel->getSize()) || (i+1!=panel->getCurrentIndex()))
8519 {
8520 putpixel(screen, tx-1+(2-sd), d->y+sd+1, scheme[jcDARK]); //right angle
8521 vline(screen, tx+(2-sd), d->y+sd+2, d->y+8+text_height(font)-1, scheme[jcDARK]); //right side
8522 vline(screen, tx+(2-sd)-1, d->y+sd+2, d->y+8+text_height(font)-(sd?1:0), scheme[jcMEDDARK]); //right side
8523 }
8524
8525 tx++;
8526 }
8527
8528 if(d->d1!=0||last_visible_tab(panel,d->d1,d->w)+1<panel->getSize())
8529 {
8530 jwin_draw_icon_button(screen,d->x+d->w-14,d->y+2, 14, 14, BTNICON_ARROW_RIGHT, 0, true);
8531 jwin_draw_icon_button(screen,d->x+d->w-28,d->y+2, 14, 14, BTNICON_ARROW_LEFT, 0, true);
8532 }
8533 }
8534
8535 if((tx+(2-sd))<(d->x+d->w))
8536 {
8537 hline(screen, tx+(2-sd)-1, d->y+8+text_height(font), d->x+d->w-1, scheme[jcLIGHT]); //ending bottom
8538 hline(screen, tx+(2-sd)-2, d->y+8+text_height(font)+1, d->x+d->w-2, scheme[jcMEDLT]); //ending bottom
8539 }
8540
8541 }
8542 }
8543 break;
8544
8545 case MSG_WANTFOCUS:
8546 // if(gui_mouse_b())
8547 ret = D_WANTFOCUS|D_REDRAW;
8548 break;
8549 case MSG_GOTFOCUS:
8550 case MSG_LOSTFOCUS:
8551 skipredraw = true;
8552 break;
8553 case MSG_CHAR:
8554 {
8555 int32_t ind = panel->getCurrentIndex();
8556 auto oldind = ind;
8557 switch(c>>8)
8558 {
8559 case KEY_LEFT:
8560 do
8561 {
8562 if(ind > 0)
8563 {
8564 --ind;
8565 }
8566 else
8567 {
8568 ind = panel->getSize()-1;
8569 }
8570 }
8571 while(ind != oldind && panel->getDisabled(ind));
8572 break;
8573 case KEY_RIGHT:
8574 do
8575 {
8576 if(ind+1 < signed(panel->getSize()))
8577 {
8578 ++ind;
8579 }
8580 else
8581 {
8582 ind = 0;
8583 }
8584 }
8585 while(ind != oldind && panel->getDisabled(ind));
8586 break;
8587 default: ind = -1;
8588 }
8589 if(ind > -1 && ind != oldind)
8590 {
8591 panel->switchTo(ind);
8592 GUI_EVENT(d, geCHANGE_SELECTION);
8593 ret |= D_USED_CHAR;
8594 }
8595 }
8596 break;
8597
8598 case MSG_CLICK:
8599 {
8600 // is the mouse on one of the tab arrows (if visible) or in the tab area?
8601 if(uses_tab_arrows(panel, d->w)&&(mouse_in_rect(d->x+d->w-28, d->y+2, 28, 14)))
8602 {
8603 if(mouse_in_rect(d->x+d->w-28, d->y+2, 14, 14))
8604 {
8605 if(do_icon_button_reset(d->x+d->w-28, d->y+2, 14, 14, BTNICON_ARROW_LEFT))
8606 {
8607 if(d->d1>0)
8608 {
8609 --d->d1;
8610 }
8611
8612 ret |= D_REDRAW;
8613 }
8614 }
8615 else if(mouse_in_rect(d->x+d->w-14, d->y+2, 14, 14))
8616 {
8617 if(do_icon_button_reset(d->x+d->w-14, d->y+2, 14, 14, BTNICON_ARROW_RIGHT))
8618 {
8619 size_t t = last_visible_tab(panel, d->d1, d->w);
8620 if(t<(panel->getSize()-1))
8621 {
8622 while(t==last_visible_tab(panel, d->d1, d->w))
8623 ++d->d1;
8624 }
8625
8626 ret |= D_REDRAW;
8627 }
8628 }
8629 }
8630 else if(is_in_rect(gui_mouse_x(),gui_mouse_y(), d->x+2, d->y+2, d->x+displayed_tabs_width(panel,((d->d1&0xFF00)>>8),d->w), d->y+text_height(font)+9))
8631 {
8632 // find out what the new tab (tb) will be (where the mouse is)
8633 int32_t newtab = discern_tab(panel, d->d1, gui_mouse_x()-d->x-2);
8634 if(newtab > -1 && newtab != panel->getCurrentIndex() && !panel->getDisabled(newtab))
8635 {
8636 panel->switchTo(newtab);
8637 GUI_EVENT(d, geCHANGE_SELECTION);
8638 }
8639 }
8640 }
8641 break;
8642 }
8643 font = oldfont;
8644 return ret;
8645 }
8646
8647
8648
8649
8650 int32_t jwin_hline_proc(int32_t msg, DIALOG *d, int32_t)
8651 {
8652 ASSERT(d);
8653
8654 if(msg==MSG_DRAW)
8655 {
8656 if(d->w < 1) return D_O_K;
8657 for(int q = 0; q <= d->d1; ++q)
8658 {
8659 if(d->d2&1)
8660 {
8661 hline(screen, d->x, d->y+q, d->x+d->w-1, d->fg);
8662 }
8663 else
8664 {
8665 hline(screen, d->x, d->y-q, d->x+d->w-1, scheme[jcMEDDARK]);
8666 hline(screen, d->x, d->y+1+q, d->x+d->w-1, scheme[jcLIGHT]);
8667 }
8668 }
8669 }
8670
8671 return D_O_K;
8672 }
8673
8674 int32_t jwin_vline_proc(int32_t msg, DIALOG *d, int32_t)
8675 {
8676 ASSERT(d);
8677
8678 if(msg==MSG_DRAW)
8679 {
8680 if(d->h < 1) return D_O_K;
8681 for(int q = 0; q <= d->d1; ++q)
8682 {
8683 if(d->d2&1)
8684 {
8685 vline(screen, d->x+q, d->y, d->y+d->h-1, d->fg);
8686 }
8687 else
8688 {
8689 vline(screen, d->x+q, d->y, d->y+d->h-1, scheme[jcMEDDARK]);
8690 vline(screen, d->x+1-q, d->y, d->y+d->h-1, scheme[jcLIGHT]);
8691 }
8692 }
8693 }
8694
8695 return D_O_K;
8696 }
8697
8698 int32_t jwin_editbox_proc(int32_t msg, DIALOG *d, int32_t c)
8699 {
8700 return d_editbox_proc(msg, d, c);
8701 }
8702
8703 //centers dialog based on first object, which should be the containing window
8704 3548 void jwin_center_dialog(DIALOG *dialog)
8705 {
8706 int32_t xc, yc;
8707 int32_t c;
8708 ASSERT(dialog);
8709
8710 /* how much to move by? */
8711 3548 xc = (zq_screen_w - dialog[0].w) / 2 - dialog[0].x;
8712 3548 yc = (zq_screen_h - dialog[0].h) / 2 - dialog[0].y;
8713
8714 /* move it */
8715
2/2
✓ Branch 0 taken 77153 times.
✓ Branch 1 taken 3548 times.
80701 for(c=0; dialog[c].proc; c++)
8716 {
8717 77153 dialog[c].x += xc;
8718 77153 dialog[c].y += yc;
8719 77153 }
8720 3548 }
8721 //up-left aligns dialog based on first object, which should be the containing window
8722 void jwin_ulalign_dialog(DIALOG *dialog)
8723 {
8724 int32_t xc, yc;
8725 int32_t c;
8726 ASSERT(dialog);
8727
8728 /* how much to move by? */
8729 xc = dialog[0].x;
8730 yc = dialog[0].y;
8731
8732 /* move it */
8733 for(c=0; dialog[c].proc; c++)
8734 {
8735 dialog[c].x -= xc;
8736 dialog[c].y -= yc;
8737 }
8738 }
8739
8740 //Custom slider proc
8741 int32_t d_jslider_proc(int32_t msg, DIALOG *d, int32_t c)
8742 {
8743 BITMAP *gui_bmp = screen;
8744 BITMAP *slhan = NULL;
8745 int32_t oldpos, newpos;
8746 int32_t sfg; /* slider foreground color */
8747 int32_t vert = TRUE; /* flag: is slider vertical? */
8748 int32_t hh = 7; /* handle height (width for horizontal sliders) */
8749 int32_t hmar; /* handle margin */
8750 int32_t slp; /* slider position */
8751 int32_t mp; /* mouse position */
8752 int32_t irange;
8753 int32_t slx, sly, slh, slw;
8754 int32_t msx, msy;
8755 int32_t retval = D_O_K;
8756 int32_t upkey, downkey;
8757 int32_t pgupkey, pgdnkey;
8758 int32_t homekey, endkey;
8759 int32_t delta;
8760 fixed slratio, slmax, slpos;
8761 typedef int32_t (*SLIDER_TYPE)(void*, int32_t);
8762 SLIDER_TYPE proc = NULL;
8763 //int32_t (*proc)(void *cbpointer, int32_t d2value);
8764 int32_t oldval;
8765 ASSERT(d);
8766
8767 /* check for slider direction */
8768 if(d->h < d->w)
8769 vert = FALSE;
8770
8771 /* set up the metrics for the control */
8772 if(d->dp != NULL)
8773 {
8774 slhan = (BITMAP *)d->dp;
8775
8776 if(vert)
8777 hh = slhan->h;
8778 else
8779 hh = slhan->w;
8780 }
8781
8782 hmar = hh/2;
8783 irange = (vert) ? d->h : d->w;
8784 slmax = itofix(irange-hh);
8785 slratio = slmax / (d->d1);
8786 slpos = slratio * d->d2;
8787 slp = fixtoi(slpos);
8788
8789 switch(msg)
8790 {
8791
8792 case MSG_DRAW:
8793 sfg = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : d->fg;
8794
8795 if(vert)
8796 {
8797 rectfill(gui_bmp, d->x, d->y, d->x+d->w/2-2, d->y+d->h-1, d->bg);
8798 rectfill(gui_bmp, d->x+d->w/2-1, d->y, d->x+d->w/2+1, d->y+d->h-1, sfg);
8799 rectfill(gui_bmp, d->x+d->w/2+2, d->y, d->x+d->w-1, d->y+d->h-1, d->bg);
8800 }
8801 else
8802 {
8803 rectfill(gui_bmp, d->x, d->y, d->x+d->w-1, d->y+d->h/2-2, d->bg);
8804 rectfill(gui_bmp, d->x, d->y+d->h/2-1, d->x+d->w-1, d->y+d->h/2+1, sfg);
8805 rectfill(gui_bmp, d->x, d->y+d->h/2+2, d->x+d->w-1, d->y+d->h-1, d->bg);
8806 }
8807
8808 /* okay, background and slot are drawn, now draw the handle */
8809 if(slhan)
8810 {
8811 if(vert)
8812 {
8813 slx = d->x+(d->w/2)-(slhan->w/2);
8814 sly = d->y+(d->h-1)-(hh+slp);
8815 }
8816 else
8817 {
8818 slx = d->x+slp;
8819 sly = d->y+(d->h/2)-(slhan->h/2);
8820 }
8821
8822 draw_sprite(gui_bmp, slhan, slx, sly);
8823 }
8824 else
8825 {
8826 /* draw default handle */
8827 if(vert)
8828 {
8829 slx = d->x;
8830 sly = d->y+(d->h)-(hh+slp);
8831 slw = d->w-1;
8832 slh = hh-1;
8833 }
8834 else
8835 {
8836 slx = d->x+slp;
8837 sly = d->y;
8838 slw = hh-1;
8839 slh = d->h-1;
8840 }
8841
8842 /* draw body */
8843 rectfill(gui_bmp, slx+2, sly, slx+(slw-2), sly+slh, sfg);
8844 vline(gui_bmp, slx+1, sly+1, sly+slh-1, sfg);
8845 vline(gui_bmp, slx+slw-1, sly+1, sly+slh-1, sfg);
8846 vline(gui_bmp, slx, sly+2, sly+slh-2, sfg);
8847 vline(gui_bmp, slx+slw, sly+2, sly+slh-2, sfg);
8848 vline(gui_bmp, slx+1, sly+2, sly+slh-2, d->bg);
8849 hline(gui_bmp, slx+2, sly+1, slx+slw-2, d->bg);
8850 putpixel(gui_bmp, slx+2, sly+2, d->bg);
8851 }
8852
8853 if(d->flags & D_GOTFOCUS)
8854 dotted_rect(gui_bmp, d->x, d->y, d->x+d->w-1, d->y+d->h-1, sfg, d->bg);
8855
8856 break;
8857
8858 case MSG_WANTFOCUS:
8859 case MSG_LOSTFOCUS:
8860 return D_WANTFOCUS;
8861
8862 case MSG_KEY:
8863 if(!(d->flags & D_GOTFOCUS))
8864 return D_WANTFOCUS;
8865 else
8866 return D_O_K;
8867
8868 case MSG_CHAR:
8869 /* handle movement keys to move slider */
8870 c >>= 8;
8871
8872 if(vert)
8873 {
8874 upkey = KEY_UP;
8875 downkey = KEY_DOWN;
8876 pgupkey = KEY_PGUP;
8877 pgdnkey = KEY_PGDN;
8878 homekey = KEY_END;
8879 endkey = KEY_HOME;
8880 }
8881 else
8882 {
8883 upkey = KEY_RIGHT;
8884 downkey = KEY_LEFT;
8885 pgupkey = KEY_PGDN;
8886 pgdnkey = KEY_PGUP;
8887 homekey = KEY_HOME;
8888 endkey = KEY_END;
8889 }
8890
8891 if(c == upkey)
8892 delta = 1;
8893 else if(c == downkey)
8894 delta = -1;
8895 else if(c == pgdnkey)
8896 delta = -d->d1 / 16;
8897 else if(c == pgupkey)
8898 delta = d->d1 / 16;
8899 else if(c == homekey)
8900 delta = -d->d2;
8901 else if(c == endkey)
8902 delta = d->d1 - d->d2;
8903 else
8904 delta = 0;
8905
8906 if(delta)
8907 {
8908 oldpos = slp;
8909 oldval = d->d2;
8910
8911 //while (true) {
8912 for(; ;) //thank you, MSVC ~pkmnfrk
8913 {
8914 d->d2 = d->d2+delta;
8915 slpos = slratio*d->d2;
8916 slp = fixtoi(slpos);
8917
8918 if((slp != oldpos) || (d->d2 <= 0) || (d->d2 >= d->d1))
8919 break;
8920 }
8921
8922 if(d->d2 < 0)
8923 d->d2 = 0;
8924
8925 if(d->d2 > d->d1)
8926 d->d2 = d->d1;
8927
8928 retval = D_USED_CHAR;
8929
8930 if(d->d2 != oldval)
8931 {
8932 /* call callback function here */
8933 if(d->dp2)
8934 {
8935 proc = (SLIDER_TYPE)(d->dp2);
8936 retval |= (*proc)(d->dp3, d->d2);
8937 }
8938
8939 GUI_EVENT(d, geCHANGE_VALUE);
8940
8941 object_message(d, MSG_DRAW, 0);
8942 }
8943 }
8944
8945 break;
8946
8947 case MSG_WANTWHEEL:
8948 return 1;
8949
8950 case MSG_WHEEL:
8951 oldval = d->d2;
8952 d->d2 = MID(0, d->d2+c, d->d1);
8953
8954 if(d->d2 != oldval)
8955 {
8956 /* call callback function here */
8957 if(d->dp2)
8958 {
8959 proc = (SLIDER_TYPE)(d->dp2);
8960 retval |= (*proc)(d->dp3, d->d2);
8961 }
8962
8963 GUI_EVENT(d, geCHANGE_VALUE);
8964 object_message(d, MSG_DRAW, 0);
8965 retval |= D_REDRAWME;
8966 }
8967
8968 break;
8969
8970 case MSG_CLICK:
8971 /* track the mouse until it is released */
8972 mp = slp;
8973
8974 while(gui_mouse_b())
8975 {
8976 msx = gui_mouse_x();
8977 msy = gui_mouse_y();
8978 oldval = d->d2;
8979
8980 if(vert)
8981 mp = (d->y+d->h-hmar)-msy;
8982 else
8983 mp = msx-(d->x+hmar);
8984
8985 if(mp < 0)
8986 mp = 0;
8987
8988 if(mp > irange-hh)
8989 mp = irange-hh;
8990
8991 slpos = itofix(mp);
8992 slmax = fixdiv(slpos, slratio);
8993 newpos = fixtoi(slmax);
8994
8995 if(newpos != oldval)
8996 {
8997 d->d2 = newpos;
8998
8999 /* call callback function here */
9000 if(d->dp2 != NULL)
9001 {
9002 proc = (SLIDER_TYPE)(d->dp2);
9003 retval |= (*proc)(d->dp3, d->d2);
9004 }
9005
9006 GUI_EVENT(d, geCHANGE_VALUE);
9007 object_message(d, MSG_DRAW, 0);
9008 }
9009
9010 /* let other objects continue to animate */
9011 broadcast_dialog_message(MSG_IDLE, 0);
9012 update_hw_screen();
9013 }
9014
9015 break;
9016 }
9017
9018 return retval;
9019 }
9020
9021 // This is only used by jwin_check_proc and jwin_radio_proc.
9022 int32_t d_jwinbutton_proc(int32_t msg, DIALOG *d, int32_t)
9023 {
9024 BITMAP *gui_bmp;
9025 int32_t state1, state2;
9026 int32_t black;
9027 int32_t swap;
9028 int32_t g;
9029 ASSERT(d);
9030
9031 gui_bmp = screen;
9032
9033 switch(msg)
9034 {
9035 case MSG_DRAW:
9036 {
9037 if(d->flags & D_SELECTED)
9038 {
9039 g = 1;
9040 state1 = d->bg;
9041 state2 = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : d->fg;
9042 }
9043 else
9044 {
9045 g = 0;
9046 state1 = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : d->fg;
9047 state2 = d->bg;
9048 }
9049
9050 rectfill(gui_bmp, d->x+1+g, d->y+1+g, d->x+d->w-3+g, d->y+d->h-3+g, state2);
9051 rect(gui_bmp, d->x+g, d->y+g, d->x+d->w-2+g, d->y+d->h-2+g, state1);
9052 gui_textout_ex(gui_bmp, (char *)d->dp, d->x+d->w/2+g, d->y+d->h/2-text_height(font)/2+g, state1, -1, TRUE);
9053
9054 if(d->flags & D_SELECTED)
9055 {
9056 vline(gui_bmp, d->x, d->y, d->y+d->h-2, d->bg);
9057 hline(gui_bmp, d->x, d->y, d->x+d->w-2, d->bg);
9058 }
9059 else
9060 {
9061 black = makecol(0,0,0);
9062 vline(gui_bmp, d->x+d->w-1, d->y+1, d->y+d->h-2, black);
9063 hline(gui_bmp, d->x+1, d->y+d->h-1, d->x+d->w-1, black);
9064 }
9065
9066 if((d->flags & D_GOTFOCUS) &&
9067 (!(d->flags & D_SELECTED) || !(d->flags & D_EXIT)))
9068 dotted_rect(gui_bmp, d->x+1+g, d->y+1+g, d->x+d->w-3+g, d->y+d->h-3+g, state1, state2);
9069
9070 break;
9071 }
9072 case MSG_WANTFOCUS:
9073 return D_WANTFOCUS;
9074
9075 case MSG_KEY:
9076 {
9077 /* close dialog? */
9078 if(d->flags & D_EXIT)
9079 {
9080 return D_CLOSE;
9081 }
9082
9083 /* or just toggle */
9084 d->flags ^= D_SELECTED;
9085 GUI_EVENT(d, geTOGGLE);
9086 object_message(d, MSG_DRAW, 0);
9087 break;
9088 }
9089
9090 case MSG_CLICK:
9091 {
9092 /* what state was the button originally in? */
9093 state1 = d->flags & D_SELECTED;
9094
9095 swap = state1;
9096
9097 /* track the mouse until it is released */
9098 while(gui_mouse_b())
9099 {
9100 state2 = ((gui_mouse_x() >= d->x) && (gui_mouse_y() >= d->y) &&
9101 (gui_mouse_x() < d->x + d->w) && (gui_mouse_y() < d->y + d->h));
9102
9103 if(swap)
9104 state2 = !state2;
9105
9106 /* redraw? */
9107 bool should_redraw = false;
9108 if(((state1) && (!state2)) || ((state2) && (!state1)))
9109 {
9110 d->flags ^= D_SELECTED;
9111 GUI_EVENT(d, geTOGGLE);
9112 state1 = d->flags & D_SELECTED;
9113 object_message(d, MSG_DRAW, 0);
9114 should_redraw = true;
9115 }
9116
9117 /* let other objects continue to animate */
9118 int r = broadcast_dialog_message(MSG_IDLE, 0);
9119 if (r & D_REDRAWME) should_redraw = true;
9120
9121 if (should_redraw)
9122 {
9123 update_hw_screen();
9124 }
9125 }
9126
9127 if(d->dp3 != NULL)
9128 {
9129 //object_message(d, MSG_DRAW, 0);
9130 typedef int32_t (*funcType)(void);
9131 funcType func=reinterpret_cast<funcType>(d->dp3);
9132
9133 return func();
9134 }
9135
9136 /* should we close the dialog? */
9137 if(d->flags & D_EXIT)
9138 {
9139 return D_CLOSE;
9140 }
9141 break;
9142 }
9143 }
9144
9145 return D_O_K;
9146 }
9147
9148 //Misc bitmap drawing
9149 void draw_x(BITMAP* dest, int x1, int y1, int x2, int y2, int color)
9150 {
9151 line(dest, x1, y1, x2, y2, color);
9152 line(dest, x1, y2, x2, y1, color);
9153 }
9154
9155 void draw_check(BITMAP* dest, int x1, int y1, int x2, int y2, int c)
9156 {
9157 if(x2 < x1)
9158 zc_swap(x2,x1);
9159 if(y2 < y1)
9160 zc_swap(y2,y1);
9161 int x3 = ((x2-x1)/2)+x1;
9162 int y3 = y2-(x3-x1);
9163 line(dest, x1, y3, x3, y2, c);
9164 line(dest, x3, y2, x2, y1, c);
9165 }
9166
9167 void draw_checkerboard(BITMAP* dest, int x, int y, int sz, optional<int> cb_sz, int offx, int offy)
9168 {
9169 if(!cb_sz)
9170 cb_sz = sz/2;
9171 int ox = -x+offx, oy = -y+offy;
9172 ditherrectfill(dest, x, y, x+sz-1, y+sz-1, vc(CheckerCol1), dithChecker, *cb_sz, ox, oy, vc(CheckerCol2));
9173 }
9174
9175 int32_t d_vsync_proc(int32_t msg,DIALOG *d,int32_t c)
9176 {
9177 // This use to be what kept 60fps, but now render_timer_wait handles that.
9178 switch(msg)
9179 {
9180 case MSG_IDLE:
9181 {
9182 broadcast_dialog_message(MSG_VSYNC, c);
9183 if(d->dp)
9184 {
9185 int32_t ret = (*(std::function<int32_t()>*)d->dp)();
9186 switch(ret)
9187 {
9188 case ONTICK_EXIT:
9189 if(d->flags&D_NEW_GUI)
9190 close_new_gui_dlg(d);
9191 return D_EXIT;
9192 case ONTICK_CLOSE:
9193 if(d->flags&D_NEW_GUI)
9194 {
9195 //Simulate a GUI_EVENT for the window proc
9196 DIALOG* window = d-1;
9197 while(window->proc != jwin_win_proc) --window;
9198 int32_t ret = new_gui_event(window-1, geCLOSE);
9199 if(ret >= 0)
9200 return ret;
9201 }
9202 return D_EXIT;
9203 case ONTICK_REDRAW:
9204 return D_REDRAW;
9205 }
9206 }
9207 break;
9208 }
9209 }
9210
9211 return D_O_K;
9212 }
9213
9214 //
9215
9216 void draw_checkbox(BITMAP *dest,int x,int y,int sz,bool value)
9217 {
9218 draw_checkbox(dest,x,y,sz,sz,value);
9219 }
9220 void draw_checkbox(BITMAP *dest,int x,int y,int wid,int hei,bool value)
9221 {
9222 jwin_draw_frame(dest, x, y, wid, hei, FR_DEEP);
9223 rectfill(dest, x+2, y+2, x+wid-3, y+hei-3, jwin_pal[jcTEXTBG]);
9224
9225 if(value)
9226 {
9227 line(dest, x+2, y+2, x+wid-3, y+hei-3, jwin_pal[jcTEXTFG]);
9228 line(dest, x+2, y+hei-3, x+wid-3, y+2, jwin_pal[jcTEXTFG]);
9229 }
9230 }
9231 void draw_dis_checkbox(BITMAP *dest,int x,int y,int wid,int hei,bool value)
9232 {
9233 jwin_draw_frame(dest, x, y, wid, hei, FR_DEEP);
9234
9235 if(value)
9236 {
9237 line(dest, x+2, y+2, x+wid-3, y+hei-3, jwin_pal[jcTEXTFG]);
9238 line(dest, x+2, y+hei-3, x+wid-3, y+2, jwin_pal[jcTEXTFG]);
9239 }
9240 }
9241
9242 bool do_scheckbox(BITMAP *dest,int x,int y,int sz,int &value, int xoffs, int yoffs)
9243 {
9244 return do_checkbox(dest,x,y,sz,sz,value,xoffs,yoffs);
9245 }
9246 bool do_checkbox(BITMAP *dest,int x,int y,int wid,int hei,int &value, int xoffs, int yoffs)
9247 {
9248 bool over=false;
9249
9250 while(gui_mouse_b())
9251 {
9252 if(isinRect(gui_mouse_x()-xoffs,gui_mouse_y()-yoffs,x,y,x+wid-1,y+hei-1))
9253 {
9254 if(!over)
9255 {
9256 value=value?0:1;
9257 draw_checkbox(dest,x,y,wid,hei,value!=0);
9258 over=true;
9259 update_hw_screen();
9260 }
9261 }
9262 else
9263 {
9264 if(over)
9265 {
9266 value=value?0:1;
9267 draw_checkbox(dest,x,y,wid,hei,value!=0);
9268 over=false;
9269 update_hw_screen();
9270 }
9271 }
9272 rest(1);
9273 }
9274
9275 return over;
9276 }
9277 bool do_checkbox_tx(BITMAP *dest,int x,int y,int wid,int hei,int &value, int txtoffs, int xoffs, int yoffs)
9278 {
9279 bool over=false;
9280
9281 while(gui_mouse_b())
9282 {
9283 if(isinRect(gui_mouse_x()-xoffs,gui_mouse_y()-yoffs,x,y,x+wid-1+txtoffs,y+hei-1))
9284 {
9285 if(!over)
9286 {
9287 value=value?0:1;
9288 draw_checkbox(dest,x,y,wid,hei,value!=0);
9289 over=true;
9290 update_hw_screen();
9291 }
9292 }
9293 else
9294 {
9295 if(over)
9296 {
9297 value=value?0:1;
9298 draw_checkbox(dest,x,y,wid,hei,value!=0);
9299 over=false;
9300 update_hw_screen();
9301 }
9302 }
9303 rest(1);
9304 }
9305
9306 return over;
9307 }
9308
9309 //box_out stuff
9310 static int32_t box_x = 0;
9311 static int32_t box_y = 0;
9312 static bool box_active=false;
9313 static int32_t box_store_x = 0;
9314 366 static FONT *box_title_font=font;
9315 366 static FONT *box_message_font=font;
9316 static int32_t box_style=0;
9317 static int32_t box_titlebar_height=0;
9318 static int32_t box_message_height=0;
9319 static uint8_t box_text_scale=1;
9320 static int32_t box_w=304;
9321 static int32_t box_h=176;
9322 static int32_t box_l=8;
9323 static int32_t box_r=312;
9324 static int32_t box_t=32;
9325 static int32_t box_b=208;
9326 static bool box_log=true;
9327 static char box_log_msg[480];
9328 static int32_t box_msg_pos=0;
9329 static int32_t box_store_pos=0;
9330
9331 int32_t onSnapshot2()
9332 {
9333 char buf[20];
9334 int32_t num=0;
9335
9336 do
9337 {
9338 sprintf(buf, "zelda%03d.bmp", ++num);
9339 }
9340 while(num<999 && exists(buf));
9341
9342 PALETTE temppal;
9343 get_palette(temppal);
9344 BITMAP *tempbmp=create_bitmap_ex(8,screen->w, screen->h);
9345 blit(screen,tempbmp,0,0,0,0,screen->w,screen->h);
9346 save_bitmap(buf,screen,temppal);
9347 destroy_bitmap(tempbmp);
9348 return D_O_K;
9349 }
9350
9351 void set_default_box_size()
9352 {
9353 int32_t screen_w = screen->w;
9354 int32_t screen_h = screen->h;
9355
9356 box_w=MIN(512, screen_w-16);
9357 box_h=MIN(256, (screen_h-64)&0xFFF0);
9358
9359 box_l=(screen_w-box_w)/2;
9360 box_t=(screen_h-box_h)/2;
9361 box_r=box_l+box_w;
9362 box_b=box_t+box_h;
9363 }
9364 /* resizes the box */
9365 void set_box_size(int32_t w, int32_t h)
9366 {
9367 int32_t screen_w = zq_screen_w;
9368 int32_t screen_h = zq_screen_h;
9369
9370 if(w <= 0) w = 512;
9371 if(h <= 0) h = 256;
9372 box_w=MIN(w, screen_w-16);
9373 box_h=MIN(h, (screen_h-64)&0xFFF0);
9374
9375 box_l=(screen_w-box_w)/2;
9376 box_t=(screen_h-box_h)/2;
9377 box_r=box_l+box_w;
9378 box_b=box_t+box_h;
9379 }
9380
9381 /* starts outputting a progress message */
9382 7 void box_start(int32_t style, const char *title, FONT *title_font, FONT *message_font, bool log, int32_t w, int32_t h, uint8_t scale)
9383 {
9384
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if (is_headless())
9385 7 return;
9386
9387 box_text_scale=scale;
9388 box_style=style;
9389 box_title_font=(title_font!=NULL)?title_font:font;
9390 box_message_font=(message_font!=NULL)?message_font:font;
9391 box_message_height=text_height(box_message_font)*scale;
9392 box_titlebar_height=title?text_height(box_title_font)+2:0;
9393 set_box_size(w,h);
9394 /*
9395 box_w=BOX_W;
9396 box_h=BOX_H;
9397 box_l=BOX_L;
9398 box_r=BOX_R;
9399 box_t=BOX_T;
9400 box_b=BOX_B;
9401 */
9402 box_log=log;
9403 memset(box_log_msg, 0, 480);
9404 box_msg_pos=0;
9405 box_store_pos=0;
9406
9407 if(!box_active)
9408 popup_zqdialog_start();
9409 jwin_draw_win(screen, box_l, box_t, box_r-box_l, box_b-box_t, FR_WIN);
9410
9411 if(title!=NULL)
9412 {
9413 zc_swap(font,box_title_font);
9414 jwin_draw_titlebar(screen, box_l+3, box_t+3, box_r-box_l-6, 18, title, false);
9415 zc_swap(font,box_title_font);
9416 box_titlebar_height=18;
9417 }
9418
9419
9420 box_store_x = box_x = box_y = 0;
9421 box_active = true;
9422 box_t+=box_titlebar_height;
9423 box_h-=box_titlebar_height;
9424 box_log=log;
9425 memset(box_log_msg, 0, 480);
9426 box_msg_pos=0;
9427 box_store_pos=0;
9428 7 }
9429
9430 /* outputs text to the progress message */
9431 25789 void box_out(const char *msg)
9432 {
9433
1/2
✓ Branch 0 taken 25789 times.
✗ Branch 1 not taken.
25789 string remainder = "";
9434
1/2
✓ Branch 0 taken 25789 times.
✗ Branch 1 not taken.
25789 string temp(msg);
9435
9436
1/2
✓ Branch 0 taken 25789 times.
✗ Branch 1 not taken.
25789 if(box_active)
9437 {
9438 //do primitive text wrapping
9439 uint32_t i;
9440 for(i=0; i<temp.size(); i++)
9441 {
9442 int32_t length = text_length(box_message_font,temp.substr(0,i).c_str())*box_text_scale;
9443
9444 if(length > box_r-box_l-16)
9445 {
9446 i = zc_max(i-1,0);
9447 break;
9448 }
9449 }
9450
9451 set_clip_rect(screen, box_l+8, box_t+1, box_r-8, box_b-1);
9452 if(box_text_scale == 1)
9453 textout_ex(screen, box_message_font, temp.substr(0,i).c_str(), box_l+8+box_x, box_t+(box_y+1)*box_message_height, gui_fg_color, gui_bg_color);
9454 else
9455 {
9456 int32_t length = text_length(box_message_font,temp.substr(0,i).c_str());
9457 BITMAP* tempbit = create_bitmap_ex(8, length, box_message_height);
9458 clear_bitmap(tempbit);
9459 textout_ex(tempbit, box_message_font, temp.substr(0,i).c_str(), 0, 0, gui_fg_color, gui_bg_color);
9460 stretch_blit(tempbit, screen, 0, 0, length, box_message_height/box_text_scale, box_l+8+box_x, box_t+(box_y+1)*box_message_height, length*box_text_scale, box_message_height);
9461 destroy_bitmap(tempbit);
9462 }
9463 set_clip_rect(screen, 0, 0, screen->w-1, screen->h-1);
9464 remainder = temp.substr(i,temp.size()-i);
9465 }
9466
9467
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25789 times.
25789 if(box_log)
9468 {
9469 25789 sprintf(box_log_msg+box_msg_pos, "%s", msg);
9470 25789 }
9471
9472
1/2
✓ Branch 0 taken 25789 times.
✗ Branch 1 not taken.
25789 box_x += text_length(box_message_font, msg);
9473 25789 box_msg_pos+=(int32_t)strlen(msg);
9474
9475
2/4
✓ Branch 0 taken 25789 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 25789 times.
25789 if(remainder != "")
9476 {
9477 bool oldlog = box_log;
9478 box_log = false;
9479 box_eol();
9480 box_out(remainder.c_str());
9481 box_log = oldlog;
9482 }
9483
9484 // For web, always call update_hw_screen because it yields to the main thread,
9485 // which makes long running tasks like loading a quest not block the main thread,
9486 // which would make SFX sound awful on the title screen.
9487
3/6
✓ Branch 0 taken 25789 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25789 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 25789 times.
25789 if (box_active || is_web())
9488 update_hw_screen();
9489 25789 }
9490
9491 /* calls box_out, and box_eol for newlines */
9492 void box_out_nl(const char *msg)
9493 {
9494 string line;
9495 istringstream reader(msg);
9496 while (getline(reader, line))
9497 {
9498 box_out(line.c_str());
9499 box_eol();
9500 }
9501 }
9502
9503 /* remembers the current x position */
9504 435 void box_save_x()
9505 {
9506
1/2
✓ Branch 0 taken 435 times.
✗ Branch 1 not taken.
435 if(box_active)
9507 {
9508 box_store_x=box_x;
9509 }
9510
9511 435 box_store_pos=box_msg_pos;
9512 435 }
9513
9514 /* remembers the current x position */
9515 156 void box_load_x()
9516 {
9517
1/2
✓ Branch 0 taken 156 times.
✗ Branch 1 not taken.
156 if(box_active)
9518 {
9519 box_x=box_store_x;
9520 }
9521
9522 156 box_msg_pos=box_store_pos;
9523 156 }
9524
9525 /* outputs text to the progress message */
9526 13534 void box_eol()
9527 {
9528
1/2
✓ Branch 0 taken 13534 times.
✗ Branch 1 not taken.
13534 if(box_active)
9529 {
9530 box_x = 0;
9531 box_y++;
9532
9533 if((box_y+2)*box_message_height >= box_h)
9534 {
9535 blit(screen, screen, box_l+8, box_t+(box_message_height*2), box_l+8, box_t+(box_message_height), box_w-16, box_y*box_message_height);
9536 rectfill(screen, box_l+8, box_t+box_y*box_message_height, box_l+box_w-8, box_t+(box_y+1)*box_message_height, gui_bg_color);
9537 box_y--;
9538 }
9539 }
9540
9541 13534 box_msg_pos = 0;
9542
9543
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13534 times.
13534 if(box_log)
9544 {
9545 13534 al_trace("%s", box_log_msg);
9546 13534 al_trace("\n");
9547 13534 memset(box_log_msg, 0, 480);
9548 13534 }
9549
9550
1/2
✓ Branch 0 taken 13534 times.
✗ Branch 1 not taken.
13534 if (box_active)
9551 update_hw_screen();
9552 13534 }
9553
9554 /* ends output of a progress message */
9555 697 void box_end(bool pause)
9556 {
9557
1/2
✓ Branch 0 taken 697 times.
✗ Branch 1 not taken.
697 if(box_active)
9558 {
9559 if(pause)
9560 {
9561 box_eol();
9562 box_pause();
9563 }
9564
9565 box_active = false;
9566 popup_zqdialog_end();
9567 }
9568 697 }
9569
9570 /* pauses box output */
9571 void box_pause()
9572 {
9573 if(box_active)
9574 {
9575 box_save_x();
9576 box_out("-- press a key --");
9577
9578 while(gui_mouse_b()) rest(1);
9579 while(!(keypressed() || gui_mouse_b())) rest(1);
9580 while(gui_mouse_b()) rest(1);
9581
9582 clear_keybuf();
9583 box_load_x();
9584 }
9585 }
9586